Android NavigationView Fragment State

2.5k views Asked by At

I am using the new NavigationView in order to show a navigation menu with the Android Design Support Library. I am also using a FrameLayout into the DrawerLayout to replace fragments into it.

The problem occurs when I change between fragments. I mean, when I use the NavigationView to click on another Fragment and come back again to the first one, the view has been just "cleaned" (f.e. content from ViewPagers Tabs just disappear). I don't know how to "refresh" the FrameLayout or if I have to reuse the Fragments instead of using transaction.replace().

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="?attr/actionBarSize" />
        <include layout="@layout/toolbar" />
    </RelativeLayout>
    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/drawer_header"
        app:menu="@menu/menu_drawer" />
</android.support.v4.widget.DrawerLayout>

I also use this method to switch between fragments into the FrameLayout.

private void displayFragment(int position) {
    Fragment fragment = null;
    String title = "";

    switch (position) {
        case 0:
            fragment = new FragmentA();
            title = getString(R.string.fragment_a);
            break;
        case 1:
            fragment = new FragmentB();
            title = getString(R.string.fragment_b);
            break;
        case 2:
            fragment = new FragmentC();
            title = getString(R.string.fragment_c);
            break;

        default:
            fragment = new HomeFragment();
            title = getString(R.string.app_name);
            break;
    }

    if (fragment != null) {
        fragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.content_frame, fragment);
        transaction.commit();

        drawerLayout.closeDrawers();
        setTitle(title);
    } else {
        Log.w(TAG, "Error creating fragment");
    }
}

Thanks!!

5

There are 5 answers

0
Gnzlt On BEST ANSWER

Based on this answer, the solution was to use getChildFragmentManager() instead of getSupportFragmentManager() inside fragments that contains other fragments, like ViewPagers Tabs.

3
Moinkhan On

You may have to try this when you are replacing the fragment..

transaction.replace(R.id.content_frame, fragment).addToBackStack("Any_String");
1
Mansukh Ahir On

try this

     NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
            if (navigationView != null) {
                setupDrawerContent(navigationView);
            }


     private void setupDrawerContent(NavigationView navigationView) {
            navigationView.setNavigationItemSelectedListener(
                    new NavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(MenuItem menuItem) {
                    Fragment fragment = null;
                    switch (menuItem.getItemId()) {
                        case R.id.nav_home:
                            Log.i("TAG","HOME");
                            fragment = new CheeseListFragment();
                            break;
                        case R.id.nav_messages:
                            fragment = new MessageFragment();
                            break;
                        case R.id.nav_friends:
                            fragment = new FriendsFragment();
                            break;
                        case R.id.nav_discussion:
                             fragment = new DiscussionFragment();
                            break;

                    }

                    if (fragment != null) {
                        FragmentManager fragmentManager = getSupportFragmentManager();
                        fragmentManager.beginTransaction()
                                .replace(R.id.container, fragment).commit();

                    }
                        menuItem.setChecked(true);
                        mDrawerLayout.closeDrawers();
                        return true;

                }
            });
}

You can open fragment in this way check which menu is selected in switch case and open fragment accordingly

0
Robert On

Not sure if it's same problem, here's my observation & solution:

The app got a NavigationView with say 5 items to switch 5 different fragments(A,B,C,D,E). Initially it switches fragments correctly but after switch about 5 times above, one fragment just sticks in the holder FrameLayout. All the transactions are called by replace().commit().

  • Choose A
  • Choose B
    ...
    ...
  • Choose C
  • Choose A (C just stay in the holder with A underneath)
  • Choose B (C just stay in the holder with B underneath)

I found fragment A actually covered by fragment C because of screen orientation changed. The fragment transaction was committed but Somehow fragment C just didn't got replaced. I even tried with getSupportFragmentManager().findFragmentByTag() to locate the previous fragment. Nothing worked.

So for solution I'm not sure if it's legit but worked: ```

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/rootLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:theme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>


    <FrameLayout
        android:id="@+id/a_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <FrameLayout
        android:id="@+id/b_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <FrameLayout
        android:id="@+id/c_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <FrameLayout
        android:id="@+id/d_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <FrameLayout
        android:id="@+id/e_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>

<android.support.design.widget.NavigationView
    android:id="@+id/navigation"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:itemIconTint="#333"
    app:itemTextColor="#333"
    app:menu="@menu/navigation_drawer_items" />

```

As you can see there're 5 FrameLayout containers for each fragment. When navigation item chosen one of the container set to VISIBLE the others set to be GONE. And worked more smooth then fragment transaction. Hope get you some ideas.

--Edit Some say using attach/detach instead of replace. https://stackoverflow.com/a/20959779/164005

I'll give a try. Let me know if you find something.

0
Tulsi On

I think this solution should work for as It did for me. In your activity make the following changes ...and dnt forget to override onbackpressed button in your activity.....it loads the fragment in your fragment manager and gives it back on button pressed if there is any... otherwise sends the user to home screen (as it can be customized by you)

fragmentManager = getSupportFragmentManager();
    ChatWithUs myFragment0 = new ChatWithUs();
    FragmentTransaction ft = fragmentManager.beginTransaction();
    ft.replace(R.id.frameholder, myFragment0);
    ft.addToBackStack("chat_fragment");
    ft.commit();
    Log.i(MainActivity.TAG, "this is create method last line");

@Override
public void onBackPressed() {
    fragmentManager = getSupportFragmentManager();
    int backCount = fragmentManager.getBackStackEntryCount();
    //Log.i(MainActivity.TAG, String.valueOf(backCount));
    if((backCount > 1)){
        //Log.i(MainActivity.TAG, String.valueOf(backCount)) ;
        //Log.i(MainActivity.TAG, "im here") ;
        fragmentManager.popBackStack();
        Log.i(MainActivity.TAG, String.valueOf(fragmentManager.getBackStackEntryCount()));
    }
    else{
        //super.onBackPressed();
        //Log.i(MainActivity.TAG, String.valueOf(fragmentManager.getBackStackEntryCount())) ;
        Intent a = new Intent(Intent.ACTION_MAIN);
        a.addCategory(Intent.CATEGORY_HOME);
        a.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(a);
    }

}`