Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ok to update fragments instead of creating new instances?

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 image 949
Julian A. Avatar asked Jan 30 '12 09:01

Julian A.


2 Answers

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.

like image 122
TalkLittle Avatar answered Oct 22 '22 11:10

TalkLittle


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

like image 31
Luigi Spezia Avatar answered Oct 22 '22 12:10

Luigi Spezia