简体   繁体   中英

save fragment state in a bottom navigation bar

I have an activity, which basically is a navigation bottom bar containing fragments. If the the user is logged in, the bottom navigation shows 4 fragments: market, favorite, upload and profile. If the user is a guest, there are two fragments: market and login.

Before, every time someone swapped from a fragment to another, it was generated again. However, I wanted to conserve the state of the fragment, so if someone applied a filter in the market and came back, it had to keep the filter applied. I tried implementing this solution https://medium.com/@oluwabukunmi.aluko/bottom-navigation-view-with-fragments-a074bfd08711 but I feel is not the best so far.

The code of the nav activity is:

public class NavigationActivity extends AppCompatActivity {

    final Fragment market= new MarketFragment();
    final Fragment favorite = new FavoriteFragment();
    final Fragment updateProduct = new AddProductFragment();
    final Fragment userProfile = new UserProfileFragment();
    final Fragment loginregister = new LoginOrRegisterFragment();
    final FragmentManager fm = getSupportFragmentManager();
    Fragment active = market;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(UnipopApp.usuariLoggejat.getUserLogged() != null){
            setContentView(R.layout.main);
        }
        else{
            setContentView(R.layout.main_guest);
        }
        setUpNavigation();
    }

    public void setUpNavigation() {
        BottomNavigationView bottomNavigationView;
        if(UnipopApp.usuariLoggejat.getUserLogged() != null) {
            bottomNavigationView = findViewById(R.id.bottom_navigation);
            bottomNavigationView.setOnNavigationItemSelectedListener(mOnNavegationItemSelectedListener);
            fm.beginTransaction().add(R.id.nav_host_fragment, favorite, "2").hide(favorite).commit();
            fm.beginTransaction().add(R.id.nav_host_fragment, updateProduct, "3").hide(updateProduct).commit();
            fm.beginTransaction().add(R.id.nav_host_fragment, userProfile, "5").hide(userProfile).commit();
            fm.beginTransaction().add(R.id.nav_host_fragment, market, "1").commit();
        }
        else {
            bottomNavigationView = findViewById(R.id.bottom_navigation_guest);
            bottomNavigationView.setOnNavigationItemSelectedListener(mOnNavegationItemSelectedListener);
            fm.beginTransaction().add(R.id.nav_host_fragment_guest, loginregister, "6").hide(loginregister).commit();
            fm.beginTransaction().add(R.id.nav_host_fragment_guest, market, "1").commit();
        }
    }

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavegationItemSelectedListener
        = new BottomNavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()){
                case R.id.action_home:
                    fm.beginTransaction().hide(active).show(market).commit();
                    active = market;
                    return true;
                case R.id.action_favorites:
                    fm.beginTransaction().hide(active).show(favorite).commit();
                    active = favorite;
                    return true;
                case R.id.addProduct_fragment:
                    fm.beginTransaction().hide(active).show(updateProduct).commit();
                    active = updateProduct;
                    return true;
                case R.id.action_user_profile:
                    fm.beginTransaction().hide(active).show(userProfile).commit();
                    active = userProfile;
                    return true;
                case R.id.action_user_profile_guest:
                    fm.beginTransaction().hide(active).show(loginregister).commit();
                    active = loginregister;
                    return true;
            }
            return false;
        }
    };
}

It works but I had to delete the nav graph... However, the thing is that when someone marks a product as favorite in the market and moves to the favorite fragment, it does not appear. Obviously, it just shows up the fragment again, it does not generate it back with the call from the server.

I am looking for other options because I don't like this solution. If someone can lend me a hand, it would be great.

Thanks

Recommended solution using Bottom Navigation View and Fragment Navigation. Use Activity's SharedViewModel to persist the states of all the navigation fragments.

Layout XML (rees/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:labelVisibilityMode="labeled"
    app:menu="@menu/bottom_navigation_menu" />

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/nav_host_fragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:navGraph="@navigation/core_navigation" />

</androidx.constraintlayout.widget.ConstraintLayout>

Navigation XML (res/navigation/core_navigation.xml)

<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
app:startDestination="@+id/navigation_feed">

<fragment
    android:id="@+id/navigation_home"
    android:name="com.example.HomeFragment"
    android:label="@string/home_title"
    tools:layout="@layout/home_fragment" />

<fragment
    android:id="@+id/navigation_favorites"
    android:name="com.example.FavoritesFragment"
    android:label="@string/favorites_title"
    tools:layout="@layout/favorites_fragment" />

<!--Fill this with other fragments like above-->

</navigation>

Menu XML (res/menu/bottom_navigation_menu.xml)

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:id="@+id/navigation_home"
    android:enabled="true"
    android:icon="@drawable/ic_home"
    android:title="@string/home_title"/>
<item
    android:id="@+id/navigation_favorites"
    android:enabled="true"
    android:icon="@drawable/ic_favorites"
    android:title="@string/favorites_title"/>

<!--Fill this with other fragments like above-->

</menu>

Activity

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setupNavigation()
    }

    private fun setupNavigation() {
        val navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
        binding.bottomNavigation.setupWithNavController(navController)
    }
}

You can save filter selection in fragment's viewmodel.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM