javaandroidandroid-fragmentsonsaveinstancestate

Save state when navigating between fragments


I'm working on an app and I have a menu with a NavigationDrawer to navigate between fragments. In one of the fragments I make a call to the backend and then save the results in a list. When I navigate to another fragment and back, the results are gone, but I'd like to save the contents of the list temporarily. I wanted to use onSaveInstanceState(), but that method doesn't seem to get called ever. I also looked if the data is still in the fields when I return to the fragment, but that also wasn't the case. I think I'm doing something wrong with the FragmentManager, but I'm not sure about it.

This is the method used for the transactions for the Fragments:

private void openFragment(Class fragmentClass) {
    Fragment fragment;
    try {
        fragment = (Fragment) fragmentClass.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
        return;
    }
    contentFrame.removeAllViews();
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction().replace(R.id.contentFrame,fragment).commit();
}

I use a switch case to determine the Fragment's class and send that to this method.

I could probably figure out a hacky-snappy way to fix this, but I'd like to fix this without too much hacky-snappy code.

I hope someone has an idea on how to fix this. Thanks in advance.

EDIT:

Here is my fragment class:

public class LGSFragment extends Fragment {

    @BindView(R.id.rvLGS)
    RecyclerView rvLGS;

    private List<LGS> lgsList;
    private LGSAdapter adapter;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //I debugged here and all fields were null at this point
        View view = inflater.inflate(R.layout.fragment_lgs,container,false);
        ButterKnife.bind(this, view);
        lgsList = new ArrayList<>();
        LinearLayoutManager manager = new LinearLayoutManager(getContext());
        rvLGS.setLayoutManager(manager);
        adapter = new LGSAdapter(lgsList);
        rvLGS.setAdapter(adapter);
        getDatabaseLGSs();
        return view;
    }

    /**
     * Method to load in the LGSs from the database
     */
    private void getDatabaseLGSs() {
        String collection = getString(R.string.db_lgs);
        FireStoreUtils.getAllDocumentsConverted(collection, LGS.class, new OperationCompletedListener() {
            @Override
            public void onOperationComplete(Result result, Object... data) {
                if (result == Result.SUCCESS) {
                    lgsList.clear();
                    List<LGS> newLGSs = (List<LGS>) data[0];
                    List<String> ids = (List<String>) data[1];
                    int i = 0;
                    for (LGS lgs : newLGSs) {
                        lgs.setId(ids.get(i));
                        lgsList.add(lgs);
                        i++;
                    }
                    adapter.notifyDataSetChanged();
                }
            }
        });
    }


    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
    }
}

Solution

  • onSaveInstanceState is not called because there is no reason to, when you navigate between fragments, the older fragment doesn't get destroyed till the OS need the space they use (low Memory).

    First of all create a back stack to keep fragments or just call addtoBackStack at the end of fragmentTransaction and then move the list initiation and data request to onCreate so it only called when the fragment is created:

        lgsList = new ArrayList<>();
        getDatabaseLGSs();
    

    and after that every time you get back to fragment the view is recreated with available data.

    Update: Instead of keeping an reference on your own, you can add the fragment to the backstack and then retrieve it using corresponding tag. This let's fragmentManager manages the caching by itself. And the second time you access a fragment, it doesn't gets recreated:

    @Override
    public void onNavigationDrawerItemSelected(@NonNull MenuItem item) {
        if (item.isChecked())
            return;
    
        item.setChecked(true);
        setTitle(item.getTitle());
    
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        Fragment currentlyShown = fragmentManager.findFragmentByTag(currentlyShownTag);
    
        Fragment dest;
        switch (item.getItemId()){
            case R.id.nav_lgs:
                dest = fragmentManager.findFragmentByTag(LGSFragment.class.getName());
                if (dest == null) {
                    Log.d("TRANSACTION", "instanciating new fragment");
                    dest = new LGSFragment();
                    currentlyShownTag = LGSFragment.class.getName();
                    transaction.add(R.id.contentFrame, dest, LGSFragment.class.getName());
                }
                break;
                ...
    
    
        }
    
        if(currentlyShown != null)
            transaction.hide(currentlyShown);
    
        transaction.show(dest);
        transaction.commit();
        drawerLayout.closeDrawers();
        return true;
    }