I want to rewrite my activities to dialogs, and I want to replace dialogs programmatically. I tried fragments staticaly and it is works fine. When I programmatically call fragment and debug it with breakpoints I don't understand why its lifecycle starts from onCreate() and ends on it... Why from onCreate() and don't from onAttach() like when I call it statically? here is my code, help me plz!!!
base_activity.xml `
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/base_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/base_fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</android.support.v4.widget.DrawerLayout>
`
BaseActivity.java
public class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.base_activity);
DietsFragment dietsFragment = new DietsFragment();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.base_fragment_holder, dietsFragment);
fragmentTransaction.commit();
}
}
DietsFragment.java
public class DietsFragment extends Fragment
implements AdapterView.OnItemClickListener,
View.OnClickListener {
public FragmentEventListener fragmentEventListener;
Cursor diets;
DietAdapter adapter;
DietHelper helper;
ListView listView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.activity_diets, container, false);
listView = (ListView) view.findViewById(R.id.act_diets_lv_diets);
if (listView != null) {
listView.setOnItemClickListener(this);
}
FloatingActionButton floatingActionButton = (FloatingActionButton) view.findViewById(R.id.act_diets_fab);
if (floatingActionButton != null)
floatingActionButton.setOnClickListener(this);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
setHelper(new DietHelper(getActivity()));
setDiets(getHelper().getAllTableRecordsCursor());
setAdapter(new DietAdapter(getActivity(), getDiets()));
listView.setAdapter(getAdapter());
fragmentEventListener = (FragmentEventListener) getActivity();
}
public void setDiets (Cursor diets) {
this.diets = diets;
}
public void setAdapter (DietAdapter adapter) {
this.adapter = adapter;
}
public void setHelper (DietHelper helper) {
this.helper = helper;
}
public Cursor getDiets() {
return diets;
}
public DietAdapter getAdapter() {
return adapter;
}
public DietHelper getHelper() {
return helper;
}
}
in DietsFragment and BaseActivity i hide its implementetions of OnClickListener, OnItemClickListener and FragmentEventListener, cause it works fine when i add fragment in BaseActivity statically from xml with
I've just found my mistake... I overloaded findViewbyId(int resId) in BaseActivity and that all my problem, and now i'm asking myself WHY I OVERLOAD THAT METHOD WHAT WAS I WANTED TO DO WITH IT?
Related
I am trying to only show my FloatingActionButton on one fragment and hide in the rest. I have tried multiple answers and nothing is working. I tried this solution:
Hide a Floating Action Button of another Layout
But it isn't working. I tried adding buttons on two of the fragments, one that shows and one that hides the FAB and that works, but once I remove the button, it won't show automatically. Here is my code:
hidden_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
shown_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
HiddenFragment.java:
public class HiddenFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
View view = inflater.inflate(R.layout.hidden_fragment, container, false);
final FloatingActionButton fab = ((MainActivity) getActivity()).getFloatingActionButton();
if (fab != null) {
((MainActivity) getActivity()).hideFloatingActionButton();
}
return view;
}
}
ShownFragment.java:
public class ShownFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
View view = inflater.inflate(R.layout.hidden_fragment, container, false);
final FloatingActionButton fab = ((MainActivity) getActivity()).getFloatingActionButton();
if (fab != null) {
((MainActivity) getActivity()).showFloatingActionButton();
}
return view;
}
}
In my MainActivity.java I have this:
public FloatingActionButton getFloatingActionButton() {
return fab;
}
public void showFloatingActionButton() {
fab.show();
}
public void hideFloatingActionButton() {
fab.hide();
}
The way I currently have it doesn't work. When I launch the app, the first fragment launched is the HiddenFragment. But when I go to the ShownFragment, the FAB doesn't appear. I tried a different approach, I added a button to each fragment and added the showFloatingActionButton() and hideFloatingActionButton() to the buttons and that works. Does anyone know what I am doing wrong?
For showing/hiding a FloatingActionButton with Fragments in a ViewPager, just use a ViewPager.OnPageChangeListener and show the FloatingActionButton for the positions you want, and hide it for the positions you want.
This would go in the Activity:
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
switch (position) {
case 0:
fab.hide();
break;
case 1:
fab.show();
break;
case 3:
fab.hide();
break;
default:
fab.hide();
break;
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Hide the floating button from other fragment. It work in my case.
in MainActivity.java add:
private ActivityMainBinding binding;
public FloatingActionButton getFloatingActionButton() {
return binding.fab;
}
onCreateView in SecondFragment:
private FloatingActionButton floatingButton;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
floatingButton = ((MainActivity) getActivity()).getFloatingActionButton();
floatingButton.hide();
...
}
I am meeting with Fragment for the first time. So it is a bit complicated to me. I am reading a tutorial at android-hive. But I am unable to understand a point. There are something I don't understand.
There are oneFragment(), twoFragment()... But I can't initiate them. So, please complete any of those... oneFragmemt() or twoFragment() from this link. I will be so pleased. Help me...
Muhamar, you always need to initiate the fragment inside an activity. If your fragment 1 has this code:
public class OneFragment extends Fragment{
public OneFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_one, container, false);
}
}
then in the main activity you can initiate like in the tutorial says:
public class MainActivity extends AppCompatActivity {
//blabla
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//blablabla
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new OneFragment(), "ONE");
//blabla
viewPager.setAdapter(adapter);
}
In this case the main activity is using an adapter to display more than one fragment, so you should have in your code more the file of the adapter, which you can find also in the tutorial.
UPDATE:
if you don't want to initalize the fragment with the adapter, you have to do two things to initialize the fragment:
1) Put fragment in layout: in the layout of your main activity you have to include a fragment and identify it (in this example android:id="#+id/headlines_fragment"):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="#+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
2) Insert the fragment in your main activity: with the following code you can add the freagment in your activity:
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
OneFragment firstFragment = new OneFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.headlines_fragment, firstFragment).commit();
}
}
UPDATE 2: to initialize from the adapter you just have to add it on the main activity, as the tutorial says. add this class on main activity:
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Hope it helps ;)
I tried to change a TextView in Activity of Fragment in three cases, but I can't change the TextView.
Is there any solution to change a TextView of Fragment in own Fragment_Activity or Main_Activity?
Fragment.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
TextView textView = (TextView) getView().findViewById(R.id.textView1);
textView.setText("Done!");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank_fragment2, container, false);
TextView tv = (TextView) view.findViewById(R.id.textView1);
tv.setText("Done!");
return view;
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TextView tv = (TextView) getView().findViewById(R.id.textView1);
tv.setText("Done!");
}
Fragment.xml
...
<TextView
android:textColor="#color/myBlack"
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
....
calling fragment class for view in MainActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_weixin);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
instance = this;
...
View view2 = mLi.inflate(R.layout.fragment_blank_fragment2, null);
views.add(view2);
...
}
Thing to know
In onCreate of fragment getView() returns null because still view in not created.
Create a method in fragment to set value for the TextView from activity using fragment instance.
Example :
Fragment
public class Fragment1 extends Fragment {
TextView tv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank_fragment2, container, false);
tv = (TextView) view.findViewById(R.id.textView1);
tv.setText("Done!");
return view;
}
public void setViewText(String text){
tv.setText(text);
}
}
Activity
public class MyActivity extends FragmentActivity {
Fragment1 fragment1;
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity_fragment);
//as you are using static fragment so create fragment instance using findFragmentById(id)
fragment1 = (Fragment1) getSupportFragmentManager().findFragmentById(R.id.fragment1);
fragment1.setViewText("Message");
}
}
Visit Official doc Communicating with Other Fragments
Because we can't see the whole Fragment.xml file or the the xml of your main activity i can't tell for sure what's the problem but it seems like you may have not specified the fragment class in the Fragment.xml file so the oncreate never gets called. I would suggest you add the fragment attribute in your main_weixin xml and that you remove the view2 inflation in your main activity then you could simply add this in your main_weixin.xml:
<fragment
android:name="your_package_name.Fragment"
android:id="#+id/fragment_id"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Here is my the problem, I have an activity, which includes a Fragment that has a ViewPager using (FragmentStatePagerAdapter), all works perfect when the Activity loads for the first time, but when setting setRetainInstance(true) to the parent fragment (the one with the pager), and orientation changes on the activity, it causes
java.lang.IllegalStateException: No activity
When trying to add the saved fragment, here is the code:
Activity:
public class DetailActivity{
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame_layout_with_progress_container);
...
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState != null) {
Fragment f = fm.findFragmentById(R.id.container);
if(f instanceof DetailPagerFragment){
detailPagerFragment = (DetailPagerFragment) f;
}
}
}
#Override
protected void onPostResume() {
super.onPostResume();
//If fragment is null, create a new instance
if(detailPagerFragment==null){
detailPagerFragment =
DetailContainerFragment.newInstance(details, initialPosition);
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, detailPagerFragment);
ft.commit();
}
Note: that i have to save the fragment instance on onCreate because when the code reaches onStart the reference for this fragment was null (this issue is not important for the time it has something to do with the NavigationDrawer), so i need to manually save the instance of the fragment.
Activity layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/container"/>
</RelativeLayout>
ViewPager Fragmentm this class extends for DetailPagerFragment which is a custom pager fragment it only wraps common code for pagers (for example view inflation, uses inflateView method), this is why the pager is added on a fragment instead of directly to the activity:
public class DetailContainerFragment extends DetailPagerFragment {
List<Detail> details;
public static DetailContainerFragment newInstance(List<Detail> details,int selectedPosition) {
DetailContainerFragment df = new DetailContainerFragment();
df.setSelectedPosition(selectedPosition);
df.setDetails(details);
return df;
}
public void setDetails(List<Detail> details) {
this.details = details;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
/**
* Inflates the view to be used by this fragment
*
* #param inflater
* Inflater to use
* #return Inflated view
*/
#Override
public View inflateView(LayoutInflater inflater) {
return inflater.inflate(R.layout.detail_pager_fragment, null);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
DetailStatePagerAdapter detailStatePagerAdapter = new DetailStatePagerAdapter(getChildFragmentManager());
setPagerAdapter(detailStatePagerAdapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
private class DetailStatePagerAdapter extends FragmentStatePagerAdapter {
public DetailStatePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return DetailFragment.newInstance(details.get(position));
}
#Override
public CharSequence getPageTitle(int position) {
return details.get(position).getTitle();
}
#Override
public int getCount() {
return details.size();
}
}
}
I had a similar problem with child fragments in a ViewPager.
The parent fragment created new instances of the child fragments to be used with the ViewPager while the adapter kept instances of the old child fragments used before the configuration change.
I ended up cleaning the ChildFragmentManager before initializing the adapter with it:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPager = (ViewPager) view.findViewById(R.id.pager);
cleanChildFragments(getChildFragmentManager());
mPagerAdapter = new MyPagerAdapter(getChildFragmentManager(), getTabFragments());
mPager.setAdapter(mPagerAdapter);
}
/**
* This is necessary to have a clean ChildFragmentManager, old fragments might be called otherwise
* #param childFragmentManager
*/
private void cleanChildFragments(FragmentManager childFragmentManager) {
List<Fragment> childFragments = childFragmentManager.getFragments();
if (childFragments != null && !childFragments.isEmpty()) {
FragmentTransaction ft = childFragmentManager.beginTransaction();
for (Fragment fragment : childFragments) {
ft.remove(fragment);
}
ft.commit();
}
}
Maybe this helps someone...
I am trying to implement fragment-Tabhost in android
MainActivity.java
public class MainActivity extends Activity {
// Declare Tab Variable
ActionBar.Tab Tab1, Tab2;
Fragment fragmentTab2 = new FragmentTab2();
//Fragment fragmentTab3 = new FragmentTab3();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getActionBar();
// Hide Actionbar Icon
actionBar.setDisplayShowHomeEnabled(false);
// Hide Actionbar Title
actionBar.setDisplayShowTitleEnabled(false);
// Create Actionbar Tabs
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set Tab Icon and Titles
Tab1 = actionBar.newTab().setText("Tab1");
//Tab2 = actionBar.newTab().setText("Tab2");
// Set Tab Listeners
Tab1.setTabListener(new TabListener(fragmentTab2));
//Tab2.setTabListener(new TabListener(fragmentTab3));
// Add tabs to actionbar
actionBar.addTab(Tab1);
//actionBar.addTab(Tab2);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
FragmentTab2.java
public class FragmentTab2 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragmenttab2, container, false);
return rootView;
}
}
FragmentTab3.java
public class FragmentTab3 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragmenttab3, container, false);
return rootView;
}
}
At present just one tab with one activity is displaying
What i am trying to do ::
click on tab1(first time) - - - - > FragmentTab2.java must display
Click on tab1(second time) - - - - > FragmentTab3.java must display
click on tab1(third time)- - - - > FragmentTab2.java must display again
This cycle must keep on repeating itself
What code changes should i need to make ?
Any IDEAS ?
I got it to work, you still need to make some adjustments, but it will get you started.
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity implements Notify, TabListener {
ActionBar.Tab tab1;
ActionBar actionBar;
int count = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction().replace(R.id.container, new FragmentTab2()).commit();
actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
tab1 = actionBar.newTab().setText("Tab1");
tab1.setTabListener(this);
actionBar.addTab(tab1);
}
//Callback
#Override
public void notifyTabListener() {
count++;
Tab tab = actionBar.newTab().setText("Tab" + count);
tab.setTabListener(this);
actionBar.addTab(tab);
}
//Tablistener
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
ft.replace(R.id.container, new FragmentTab2());
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.add(new FragmentTab2(), "Tab" + count);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
}
Notify callback:
public interface Notify {
public void notifyTabListener();
}
FragmentTab2:
public class FragmentTab2 extends Fragment implements OnClickListener {
Notify mCallback;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.f2, container, false);
LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.layout2);
layout.setOnClickListener(this);
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallback = (MainActivity) activity;
}
#Override
public void onClick(View v) {
mCallback.notifyTabListener();
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
f2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:text="Fragment2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
You need to implement TabListener and set to Tab1.setTabListener().
When onTabSelected(), repeating replace fragment1 or fragment2.