In the example on using fragments in the Android docs, when the application is in 'dualview' mode, the details fragment is recreated whenever the application needs to show details for a different title. FragmentTransaction.replace()
is used to swap out each old details fragment instance with a new one.
Is this recommended practice? Isn't it wasteful to create a new UI instance when the real intent (no pun intended) is to update what the UI shows, not the UI itself. It seems to me the only reason to create new instances is if one intends to add them to the backstack so the user can retrace steps. Otherwise, is it safe/advisable to update a fragment directly?
In the case of the example, it would mean a method along the lines of DetailsFragment.setShownIndex()
. This would be called, passing in the new title index, instead of recreating DetailsFragment
.
Suppose we have a version of the example where one activity manages both fragments, but only shows one at a time, swapping each fragment out as needed. Would it be ok for the activity to create an instance of each fragment, retain references to each, and then simply add or remove these two instances from itself as needed?
One possibly sticky consequence of this would be that, when the titles fragment is in resumed
state (i.e. in the 'foreground'), selecting a title will result in a call to DetailsFragment.setShownIndex()
at a time when the details fragment is in stopped
state.
Good idea? Bad idea?
Thanks in advance.
Like you said, the main reason to create new Fragment instances is for ease of using the back stack. It is also perfectly safe to reuse an existing Fragment (looking it up using either FragmentManager.findFragmentById()
or FragmentManager.findFragmentByTag()
). Sometimes you'll need to make good use of the Fragment methods like isVisible()
, isRemoving()
etc. so you don't illegally reference UI components when the DetailsFragment
is stopped
.
Anyway in your proposed single-pane Activity with 2 fragments, your setShownIndex
method could set a private field in DetailsFragment
which is loaded in onCreateView
or onActivityCreated
.
e.g.,
DetailsFragment df = getFragmentManager().findFragmentByTag("details");
if (df != null) {
df.setShownIndex(getSelectedIndex());
} else {
df = DetailsFragment.newInstance(getSelectedIndex());
}
fragmentTransaction.replace(R.id.frame, df, "details").commit();
In both cases, whether df is newly created or reused, onCreateView
and onActivityCreated
will be called when the DetailsFragment
gets added to the container.
But if you want a back stack, I highly recommend just creating new instances, otherwise you're just implementing your own back stack for the contents of the DetailsFragment
.
I have tried the following code and it works for me :
private void replaceFragment(Class fragmentClass, String FRAGMENT_NAME, android.support.v4.app.FragmentManager fragmentManager) {
Fragment fragment = null;
String backStateName = fragmentClass.getName(); // nome della classe del Fragment
Log.d("Fragment: ", "Creazione Fragment: "+backStateName);
Boolean fragmentExit = isFragmentInBackstack(fragmentManager, backStateName);
if (fragmentExit) { //Il Fragment è presente nello stacback
// Fragment exists, go back to that fragment
//// you can also use POP_BACK_STACK_INCLUSIVE flag, depending on flow
fragmentManager.popBackStackImmediate(fragmentClass.getName(), 0);
} else {
// se non esiste lo aggiungiamo
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Inizializzo la transazione del Fragment
android.support.v4.app.FragmentTransaction ft = fragmentManager.beginTransaction();
ft.setCustomAnimations(
R.anim.fragment_slide_left_enter,
R.anim.fragment_slide_left_exit,
R.anim.fragment_slide_right_enter,
R.anim.fragment_slide_right_exit);
ft.replace(R.id.frameLayout_contentMain, fragment, FRAGMENT_NAME);
ft.addToBackStack(fragmentClass.getName());
ft.commit();
// Recupero il numero di Fragment presenti
Integer nFragment = fragmentManager.getBackStackEntryCount();
Log.d("Fragment: ", "Numero di Fragment: "+nFragment);
}
}
To determine if the Fragment is already in StackBack execute this function :
public static boolean isFragmentInBackstack(final android.support.v4.app.FragmentManager fragmentManager, final String fragmentTagName) {
for (int entry = 0; entry < fragmentManager.getBackStackEntryCount(); entry++) {
if (fragmentTagName.equals(fragmentManager.getBackStackEntryAt(entry).getName())) {
return true;
}
}
return false;
}
I Hope I could help you
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With