Save state of fragment A when navigating from bottomNavigationView to fragment B
V

1

8

I am new to Android and I have been struggling for some time now with saving state of a fragment. My app has 5 options in the bottomNavigationView (I am using the default activity from Android). In fragment A (actually called "SearchFragment") I have a button and when clicked it sets some text in a TextBox. I want to save the state of this fragment (with the text there) when navigating to another fragment and the coming back to the fragment A (and have the text still there from the previous button click).

From the code I wrote it saves the fragment's state when changing orientation for example, but doesn't do so when navigating to other fragments and then coming back.

How could I change the code? Or is there any other method to save the current state of a fragment on navigation? I really need some help here...and thanks for your attention!

My mainActivity looks like this:

    public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            BottomNavigationView navView = findViewById(R.id.nav_view);
            // Passing each menu ID as a set of Ids because each
            // menu should be considered as top level destinations.

            AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                    R.id.navigation_search, R.id.navigation_explore, R.id.navigation_trips, R.id.navigation_groups,R.id.navigation_profile)
                    .build();

            NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
            NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
            NavigationUI.setupWithNavController(navView, navController);
        }

    }

And the fragment class looks like this:


    public class SearchFragment extends Fragment {

        private SearchViewModel searchViewModel;
        Button b;
        TextView text;
        Bundle savedState = null;

        public View onCreateView(@NonNull LayoutInflater inflater,
                                 ViewGroup container, Bundle savedInstanceState) {

            View root = inflater.inflate(R.layout.fragment_search, container, false);

            searchViewModel = ViewModelProviders.of(this).get(SearchViewModel.class);
            final TextView textView = root.findViewById(R.id.text_dashboard);
            searchViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
                @Override
                public void onChanged(@Nullable String s) {
                    textView.setText(s);
                }
            });
            Log.i("state","onCreate");
            Log.i("bundleIsNull", "" + (savedState == null));


            b  = root.findViewById(R.id.button2);
            text = root.findViewById(R.id.textView);


            b.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    text.setText("YEEEY");
                    Log.i("bundleIsNull", "" + (savedState == null));
                }
            });


            if(savedInstanceState != null && savedState == null) {
                savedState = savedInstanceState.getBundle("buttonText");
            }
            if(savedState != null) {
                text.setText(savedState.getCharSequence("buttonText"));
            }
            savedState = null;

            return root;
        }


        @Override
        public void onDestroyView() {
            super.onDestroyView();
            Log.i("state", "onDestroyView");
           savedState = saveState();
           text = null;
           b = null;
        }

        private Bundle saveState() {
            Bundle state = new Bundle();
            state.putCharSequence("buttonText", text.getText());
            return state;
        }

        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            Log.i("state", "onSaveInstanceState");
            outState.putBundle("buttonText", (savedState != null)? savedState : saveState());
        }

        @Override
        public void onPause() {
            super.onPause();
            Log.i("state","onPause");
        }
    }

Virile answered 26/3, 2020 at 20:22 Comment(1)
see this solution that create custom navigator. https://mcmap.net/q/159130/-is-there-a-way-to-keep-fragment-alive-when-using-bottomnavigationview-with-new-navcontrollerDanziger
L
9

Few facts around Android Navigation Component with Bottom Navigation Bar.

- > Fragments are always recreated (onCreate, onViewCreated, onViewDestroyed are called as soon as the user navigates to another fragment)

- > Fragment will save its state only when activity is recreated (e.g. screen rotation) , navigating between fragments doesn't save fragment's state.

I want to save the state of this fragment (with the text there) when navigating to another fragment and the coming back to the fragment A (and have the text still there from the previous button click).

This wont be possible as a new instance of FragmentA is created when you navigate back from fragmentB to Fragment A.

you can not achieve this with navigation controller as of now.

Since you are using navigation component, You should switch to using Viewmodel to solve retain fragment state issue.

Consult the following link to see how to communicate and save data between fragments using viewmodel.

https://androidwave.com/fragment-communication-using-viewmodel/

Linkman answered 26/3, 2020 at 23:23 Comment(5)
Thank you for your help !! It worked :) I added a sharedViewModel for all the fragments and now it worksVirile
Hey @Virile could you share how you did it on github or something? Thank you!Spender
with a videmodel being used for this purpose, is there a way that we can do scrollToPosition with recycler view . Since the view model keeps the latest pulled data and that is restored. We can always append data to adapter and while changing fragment update list in viewmodel and on restore, publish back in the adapter, but this always scrolls to top but not the last saved ui position and scrollToPosition would not work too. Any ideas ?Scourge
@Virile sharedViewModel save a Fragment, but doesn't save its ViewStereotomy
How to save fragment view? For example i have google / yandex map and if i use a navigation component this map fragments are recreated alwaysPerce

© 2022 - 2024 — McMap. All rights reserved.