Blacksword
Blacksword

Reputation: 331

Prevent navigation drawer Fragment from being recreated

Recently i'm working on my app to make it load faster and work better, i'm using navigation drawer in my MainActivity:

    @Override
public boolean onNavigationItemSelected(MenuItem item) {

    // Handle navigation view item clicks here.
    int id = item.getItemId();

    if (id == R.id.nav_camara) {
        LoadJson asyncTask = (LoadJson) new LoadJson(new LoadJson.AsyncResponse() {
            @Override
            public void processFinish(JSONArray output) {
                //Here you will receive the result fired from async class
                //of onPostExecute(result) method.
                //Set the fragment initially
                MainFragment fragment = new MainFragment(output);
                FragmentTransaction fragmentTransaction =
                        getSupportFragmentManager().beginTransaction();
                fragmentTransaction.add(R.id.fragment_container, fragment);
                fragmentTransaction.commit();
                // Handle the camera action
            }
        }).execute();


    } else if (id == R.id.nav_gallery) {
        //Set the fragment initially
        GalleryFragment fragment = new GalleryFragment();
        FragmentTransaction fragmentTransaction =
                getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, fragment);
        fragmentTransaction.commit();


    } else if (id == R.id.nav_search) {
        //Set the fragment initially
        FetchResualt fragment = new FetchResualt();
        FragmentTransaction fragmentTransaction =
                getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, fragment);
        fragmentTransaction.commit();
        // Handle the camera action

    } else if (id == R.id.nav_manage) {//
         Bundle bundle = new Bundle();//
        bundle.putInt("someStr",ID_OF_BEACH);//
        //Set the fragment initially//
        FragmentBeach fragment = new FragmentBeach();//
        fragment.setArguments(bundle);//
        FragmentTransaction fragmentTransaction =//
                getSupportFragmentManager().beginTransaction();//
        fragmentTransaction.replace(R.id.fragment_container, fragment);//
        fragmentTransaction.commit();//
        // Handle the camera action

    } else if (id == R.id.nav_share) {

    } else if (id == R.id.nav_send) {

    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

As you can see if we push the first menu if (id == R.id.nav_camara) it will pass a JSONArray to a Fragment class and it take like 4-5 seconds to load. So if the user navigates between menus every time he goes to nav_camara it make the app a 4 second freeze to load and as you can see everytime we choose a menu item it will recreate a new copy of fragment, so even if I make: setRetainInstance(true); in my fragment class it wont work.

What solution you suggest to prevent the app to recreate a new fragment each time we choose a menu item?

Upvotes: 0

Views: 1418

Answers (3)

Sufian
Sufian

Reputation: 6555

You will need to keep a SparseArray<Fragment> to keep the instances in memory.

Follow these steps:

  1. create a field in your Activity:

    SparseArray<Fragment> myFragments;
    
  2. initialise it in the onCreate() like:

    myFragments = new SparseArray<Fragment>();
    
  3. update your onNavigationItemSelected():

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();
    
        if (id == R.id.nav_camara) {
            // get cached instance of the fragment
            fragment = myFragments.get(INT_CONSTANT_FOR_CAM_FRAGMENT);
    
            // if fragment doesn't exist in myFragments, create one and add to it
            if (fragment == null) {
                fragment = new MainFragment();
                myFragments.put(INT_CONSTANT_FOR_CAM_FRAGMENT, fragment);
            }
    
            // now load the fragment
            FragmentTransaction fragmentTransaction =
                        getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.fragment_container, fragment);
            fragmentTransaction.commit();
    
        }
        // do the rest with others as well.
    }
    
  4. move the AsyncTask thing inside your MainFragment's onActivityCreated() or a similar lifecycle method.

Above way will let you reuse the fragments and move the logic to their correct location (your Activity shouldn't know how MainFragment loads data to initiate itself, but of course you can still keep it there, though not recommended).

Upvotes: 2

Android.K.Doe
Android.K.Doe

Reputation: 136

Declare them globally

GalleryFragment galleryFrag = new GalleryFragment();
FragmentTransaction ft;
FragmentManager fm;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    fm = getSupportFragmentManager();

    ...
}

then on your navigation selection

@Override
public boolean onNavigationItemSelected(MenuItem item) {

// Handle navigation view item clicks here.
int id = item.getItemId();

if (id == R.id.nav_search) {
    ft = fm.beginTransaction();
    ft.replace(R.id.fragment_container, galleryFrag).commit();
} 

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}

Upvotes: 0

Alex Chengalan
Alex Chengalan

Reputation: 8281

You can add a TAG while push a new fragment to the container. Then use FragmentManager#findFragmentByTag to find any fragment previously added with the same tag.

        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        Fragment oldFragment = manager.findFragmentByTag(tag);
        if (oldFragment != null)
            transaction.replace(R.id.fragment_container, oldFragment, tag);
        else
            transaction.replace(R.id.fragment_container, newInstanceOfFragment, tag);
        transaction.commit();

Upvotes: 0

Related Questions