I have a fragmentactivity that starts on Fragment A then can be change to Fragment B. If i am on Fragment B and i rotate my device. It loads the original Fragment A not Fragment B. I am Loading both Fragment A and B pragmatically. I thought android was supposed to save which Fragment i was on automatically i am not overriding onSaveInstanceState
This is how i am loading the fragments
FragmentTransaction t = this.getSupportFragmentManager()
.beginTransaction();
t.replace(R.id.fragholder, new MainFragment());
t.commit();
When you rotate your device, it destroys your Activity and recreates its. So assuming Fragment A is the default Fragment, then it is logical that it would load that when the Activity is recreated. So you would need to override onSaveInstanceState to store which Fragment is visible and then reload that Fragment in onCreate.
Reference to relevant Activity Lifecycle doc:http://developer.android.com/training/basics/activity-lifecycle/recreating.html
Just add android:configChanges="orientation|screenSize" to your manifest and android takes care of everything for you
Related
I'm having problem with fragment. Lets try to understand my issue, I have two fragment A and B. When app start with main activity,i start fragment A as you can see :
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new MusicFragment())
.commit();
When i click on a button, it starts fragment B
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
Main problem is after starting fragment B,when i pressed back to go back to fragment A , Fragment A Recreated with new state.
I don' want to recreate fragment A. I only want to start fragment from old state where i left. How to fix it ?
Instead of calling the replace method you should be calling the add method with a subsequent call to addToBackStack with an argument of null. The add method adds the fragement to the stack with a null tag and calling the addToBackStack with an argument of null then the current fragment is stopped upon commit. If the method is not called then the current fragment is destroyed and recreated when coming back.
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container,new BarFragment())
.addToBackStack(null)
.commit();
You can clearly find it in the documentation quote saying this:
If you don't call addToBackStack() when you perform a transaction that
removes a fragment, then that fragment is destroyed when the
transaction is committed and the user cannot navigate back to it.
Whereas, if you do call addToBackStack() when removing a fragment,
then the fragment is stopped and is later resumed if the user
navigates back.
Here are some points that need to be taken care while creating fragments.
Check the backstack if the fragment is already created.
If it was created previously pop it from the backstack and put it on top so that it is visible to the user.
If fragment is not present in backstack crate it and store it in backstack.
Create a method like below which will handle such situation.
private void openFragment(Fragment fragment_to_be_opened){
String fragment_to_be_opened_name = fragment_to_be_opened.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
// fetching the fragment if it is present in backstack
boolean fragment_allready_present = manager.popBackStackImmediate (fragment_to_be_opened_name, 0);
if (!fragment_allready_present){ //fragment is not present in backstack so create it and save the name in //backstack
FragmentTransaction fragment_trasition = manager.beginTransaction();
fragment_trasition.replace(R.id.fragment_container, fragment_to_be_opened);
fragment_trasition.addToBackStack(fragment_to_be_opened_name);
fragment_trasition.commit();
}
}
Now call this method from the activity to open a new fragment like
// create instance of fragment and pass it to the open fragment method
Fragment myFragment = new myFragment();
openFragment(myFragment);
How to replace Fragment_1 Fragment_2 with the ability to return back to the state and Fragment_1 (scroll, inputs, forms, other)?
enter image description here
If you use Activities, then you can use the method startActivityForResult. The work of this method perfectly shows the current task with fragments.
I do not want to save the values and then substitute them. We need that to Fragment_1 remained intact.
How to save the status of previous fragments at the opening of the new fragment_N and when you turn the screen using backstack?
Is there a ready library for the implementation of these tasks?
Instead of replacing fragment, You can add a new fragment and hide current one.
Something like this
FragmentTransaction t = getFragmentManager.beginTransaction();
t.hide(your_current_fragment);
t.add(container, new_fragment);
t.addToBackStack(TAG);
t.commit();
It will not loss the state of hidden fragment
FragmentTransaction t = getFragmentManager.beginTransaction();
t.hide(your_current_fragment);
t.add(container, new_fragment);
t.addToBackStack(TAG);
t.setCustomAnimations(R.anim.open_enter,R.anim.close_exit,R.anim.open_enter,R.anim.close_exit)
or
t.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
t.setTrans
t.commit();
replace FragmentPagerAdapter with a HorizontalScrollView contains 2FrameLayout for fragment.You can freely change fragment in FrameLayout.
Hardly can't get fragment from backstack, even start thinking of keeping in in singleton which is probably bad.
Saved to backstack like this and all time try to get it by tag or something gives me error.
Fragment fragment = UserProfileFragment.newInstance(null);
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(FRAGMENT_PLACE_RESOURCES, fragment);
trans.addToBackStack("profile");
trans.commit();
It just return me null here so I can't use this fragment. No logs.
Fragment fragment2 = getFragmentManager().findFragmentByTag("profile");
getFragmentManager().findFragmentByTag("tag")
is only used when you have added a fragment with specific tag for e.g.
fragmentTransaction.add(R.id.order_container,mProfileFragment,"profile");
or
fragmentTransaction.replace(R.id.order_container,mProfileFragment,"sometag");
Then you will be able to find this fragment by the tag.
In your case you are adding a transaction to backstack so you will not be able to find that fragment by tag. You just adding a transaction to backstack thats it not a fragment. And also your fragment was removed from the activity and destroyed so you have to revert the transaction by popping backstack instead of finding that fragment by tag.
You have to call
getFragmentManager().popBackStack("profile");
to get that fragment back to the activity and make it visible on screen.
I have an activity within it I do
FragmentTransaction trans = getFragmentManager().beginTransaction();
FragmentList fragList = new FragmentList();
trans.replace(R.id.fragList, fragList, "fragList");
to fill my frame layout with the actual fragment. That works fine. Through navigation I end up later in some other activity and some other fragment. In that new fragment I have to call a method of my list fragment to tell it that something has changed.
FragmentList listfrag = (FragmentList) getFragmentManager().findFragmentByTag("fragList");
FragmentList listfrag2 = (FragmentList) getFragmentManager().findFragmentById(R.id.fraglist);
listfrag.updateData(b);
Both, listfrag and listfrag2, are always null. Why?
Edit:
based on the answer that this is not possible from one activity to another activity. I have activity A,
On a tablet A has fragment F1 and F2, on a phone only F1. If I select something on F1, the either F2 gets updated or activity B is called to show F2. In F2 I press a save button and I want to update F1 based. So I either have to call something in the same activity (tablet) or in different acitivty (phone). How can I do this without duplicating my code for the updates?
The getFragmentManager() method gets a reference to the FragmentManager that is used within that activity.
In essence, you are creating the Fragment in one Activity, but looking for it in another. You can't do that (easily).
It sounds like you might want to use startActivityForResult() and onActivityResult() to pass data back and forth between the Activities.
Fragment lifecycle is tied to its activity, you can't call it from another activity. But in the same activity when you replace with another fragment,
Try this,
trans
.replace(R.id.fragList, fragList, "fragList")
.addToBackStack(null) // this will keep fragment when you replace with another.
.commit();
I have an activity which loads a fragment (say Fragment1) in onCreate. When the user presses a button in Fragment1, I replace Fragment1 with a new fragment, say Fragment2. The problem is that on changing orientation while in Fragment2, the activity is recreated and shows Fragment1
instead of Fragment2. (because I create Fragment1 in onCreate)
How can I stick to Fragment2 and also retain its state on orientation change?
Thanks
When a fragment transaction occurs, assign a variable so you know which fragment is being created. Then override OnSavedInstanceState and pass your variable into the bundle.
Then on orientation change, onCreate will be called and you can retrieve your variable from the savedInstanceStateBundle. You can then choose which fragment will be 'loaded' in the onCreate.