I'm working on an android application, that uses a navigation drawer to switch between two fragments. However, each time I switch, the fragment is completely recreated.
Here is the code from my main activity.
/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
android.support.v4.app.Fragment fragment;
String tag;
android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager();
switch(position) {
case 0:
if(fragmentManager.findFragmentByTag("one") != null) {
fragment = fragmentManager.findFragmentByTag("one");
} else {
fragment = new OneFragment();
}
tag = "one";
break;
case 1:
if(fragmentManager.findFragmentByTag("two") != null) {
fragment = fragmentManager.findFragmentByTag("two");
} else {
fragment = new TwoFragment();
}
tag = "two";
break;
}
fragment.setRetainInstance(true);
fragmentManager.beginTransaction().replace(R.id.container, fragment, tag).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mNavTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
I've set up some debug logging, and every time selectItem is called, one fragment is destroyed, while the other is created.
Is there any way to prevent the fragments from being recreated, and just reuse them instead?
I guess you can not directly manipulate the lifecycle mechanisms of your
Fragments
. The very fact that you canfindFragmentByTag
is not very bad. It means that the Fragment object is not recreated fully, if it is already commited. The existingFragment
just passes all the lifecycle steps eachFragment
has - that means that only UI is "recreated".It is a very convenient and useful memory management strategy - and appropriate, in most cases.
Fragment
which is gone, has the resources which have to be utilized in order to de-allocate memory.If you just cease using this strategy, the memory usage of your application could increase badly.
Nonetheless, there are retained fragments, which lifecycle is a bit different and do not correspond to the Activity they are attached to. Typically, they are used to retain some things you want to save, for example, to manage configuration changes
However, the fragment [re]creation strategy depends on the context - that is, what you would like to solve, and what are the trade-offs that you are willing to accept.
Just find the current fragment calling getFragmentById("id of your container") and then hide it and show needed fragment.
After @meredrica pointed out that replace() destroys the fragments, I went back through the FragmentManager documentation. This is the solution I've come up with, that seems to be working.
I also added this bit, but I'm not sure if it's necessary or not.
The replace method destroys your fragments. One workaround is to set them to
Visibility.GONE
, another (less easy) method is to hold them in a variable. If you do that, make sure you don't leak memory left and right.Use the attach/detach method with tags:
Detach will destroy the view hirachy but keeps the state, like if on the backstack; this will let the "not-visible" fragment have a smaller memory footprint. But mind you that you need to correctly implement the fragment lifecycle (which you should do in the first place)
The first time you add the fragment
then you detach it
and attach it again if switched back, state will be kept
But you always have to check if the fragment was added yet, if not then add it, else just attach it:
How about playing with the Visible attribute?