Home > Software engineering >  Saving Fragment state with Android BottomNavigation
Saving Fragment state with Android BottomNavigation

Time:04-16

I'm new to Android development, so I do not understand many, perhaps elementary things, perhaps even the stated topic does not fully reflect my questions, I apologize in advance, I could not formulate more precisely. Please help me with some questions.

I have a BottomNavigation in my application with three menu items. Like on a picture:

bottom nav

Initially, I did it as in the standard Android Studio example:

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private NavController navController;

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

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        BottomNavigationView navView = findViewById(R.id.nav_view);
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_update, R.id.navigation_notifications)
                .build();

        navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);

        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(binding.navView, navController);
    }
}

In this code, the menu items switch fragments, saving the state of each of them (I don’t know how exactly, it seems to be somewhere inside the navigation controller).

But now I needed the middle button to perform a different function, i.e. not to participate in switching fragments.

The only adequate way to do this is to use setOnItemSelectedListener.

Then my code will look like this:

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private NavController navController;

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

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        BottomNavigationView navView = findViewById(R.id.nav_view);
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_update, R.id.navigation_notifications)
                .build();

        navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);

        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(binding.navView, navController);

        navView.setOnItemSelectedListener(
                new NavigationBarView.OnItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        switch (item.getItemId()) {

                            case R.id.navigation_home:
                                navController.navigate(R.id.navigation_home);
                                break;
                            case R.id.navigation_update:
                                // work for middle menu item
                                break;
                            case R.id.navigation_notifications:
                                navController.navigate(R.id.navigation_notifications, savedInstanceState);
                                break;
                        }
                        return true;
                    }
                });
    }
}

It even works, except that the fragments no longer save their state. That is, for example, in the first fragment I have a RecyclerView, if I scroll it down, switch to another fragment, and then return back, then the RecyclerView is in the default state (not scrolled), that is the state has not been saved.

It turns out that in the first version of the code I can’t do individual work with the middle menu item, and in the second version the states of the fragments are not saved.

Prompt correct way to deal with this problem. So that the middle menu item can be assigned a separate job, and the state of the fragments can be saved.

CodePudding user response:

instead of using navView.setOnItemClickListener, you can use navController.addOnDestinationChangedListener, and in overrided onDestinationChanged method, you can check

if(destination.id ==  R.id.navigation_update) {
    //your custom action here
}

CodePudding user response:

I was able to solve the problem with standard tools using Navigation. I just found a menu item and added a OnClickListener to it.

BottomNavigationItemView updateBtn = findViewById(R.id.navigation_update);
updateBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
       // todo
   }
});  

Thus, both switching fragments and clicking on the middle menu item work correctly.

  • Related