2

I am following this question

how to store recyclerview data on onSaveInstanceState

I also found How to save state of view class? and Fragment save view state.

Context

I give data in form of DataModel (implements Parcelable) to recyclerview in one of my Fragments. using Bottom navifation and ROOM DB (to get and save Data).

what I have done yet

I used the code in first link and in my code. But I couldn't understand the fourth peace of code, which was used in there (I don't have a response.boddy(), Error). Anyway every time changing the view savedInstanceState = null so the code is being redone.

what I want or question

I would like to not redo the work every time changing the view via bottom navigation?

what am I doing wrong, that data are not being saved in savedInstanceState?

my Fragment view

    private ArrayList<DataModel> data;

    public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    
    root = inflater.inflate(R.layout.fragment_home, container, false);
    currentContext = getContext();
    
    
    recyclerView = (RecyclerView) root.findViewById(R.id.recyclerViewHome);
    recyclerView.setHasFixedSize(true);


    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    this.data = new ArrayList<>();
    
    adapter = new CustomAdapter(data, currentContext, 1);
    recyclerView.setAdapter(adapter);

    
    if (savedInstanceState != null) {
        
        // Retrieve the data you saved
        data = savedInstanceState.getParcelableArrayList("saved_data");

        //Call method to reload adapter record
        recyclerViewsaveInstance(data);
    } 
     else {
        
        //No data to retrieve

        dataAsynTask; //deleted, Basicly I get the data from DB, convert it to DataModel and give them to recyclerview.
    }

    return root;
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);

    Log.i("savedInstanceState", "loading");
    
    savedInstanceState.putParcelableArrayList("saved_data", this.data);
    
    super.onSaveInstanceState(savedInstanceState);

}


public void recyclerViewsaveInstance(ArrayList<DataModel> dataset)
{
    this.data = dataset;
    adapter = new CustomAdapter(dataset, getContext(), 1);
    recyclerView.setAdapter(adapter);//notify adapter about the new record
    adapter.notifyDataSetChanged();
}
  • It sounds like you're saying that the `savedInstanceState` bundle is `null` every time; this probably means that there's an issue in your `Activity` (or wherever it is that you create the `FragmentTransaction` to show your `Fragment`). Could you add that code to your question? – Ben P. Jul 27 '20 at 16:46
  • Alternatively, perhaps there's a misunderstanding about the concept of saving instance state. `onSaveInstanceState()` is called when the fragment is destroyed and recreated by a configuration change (like when you rotate your phone). If you are using bottom nav to switch to a different view and then switch back, that won't use `onSaveInstanceState()`. If you want your recyclerview data to be cached when you do this, you'll have to save it somewhere else (perhaps in the `Activity` that hosts the bottom nav and fragments). – Ben P. Jul 27 '20 at 16:50
  • I guess I am doing what you said (switching between views). Do you mean saving the hole recyclerview somehow? – programmer Erfan Jul 27 '20 at 17:01
  • I added what I had in MainActivity. – programmer Erfan Jul 27 '20 at 17:02

1 Answers1

0

I think what you want to do here is to move your AsyncTask out to the Activity level, and have your Fragment ask the Activity for the List<DataModel>.

In your Fragment's onCreateView() method, instead of writing

this.data = new ArrayList<>();

and then checking savedInstanceState and conditionally executing an AsyncTask, you could write this:

this.data = ((MyActivity) getActivity()).getData();

Then, in your Activity, you'd implement this getData() method:

public List<DataModel> getData() {
    if (data != null) {
        return data;
    } else {
        // kick off AsyncTask here
        return Collections.emptyList();
    }
}

When the AsyncTask finishes, have it update the Activity's data field and also have it notify the Fragment that new data is available. In the Fragment, you'd have a method like this:

public void onDataFetched(List<DataModel> data) {
    this.data = data;
    adapter.notifyDataSetChanged();
}

The end result of all of the above is that the Activity is now responsible for loading the data and for saving it. The Fragment doesn't know anything about the database or caching; it just knows to ask the Activity for the data whenever it is shown.

Since the Activity stays alive while you switch between Fragments with your bottom nav, it will successfully keep the data alive when you switch tabs.

Ben P.
  • 52,661
  • 6
  • 95
  • 123
  • feedback: This was Perfect. But I couldn't get my data from Asyntask (which was an interface methode called by Asyntask, after it was finished). I tried waiting for the result of Asyntask but It wasn't happening and the emulator was hanging too. I guess there is some problem with my Interface. Any way I did what I was doing before, except a getter and setter methode in my "Activity" so if there was no data in Activity (which is just the first time), than I would get data from DB and save it in "Activity". After that data are always saved in "Activity". – programmer Erfan Jul 27 '20 at 19:25
  • `AsyncTask` was being used in 2020? – IgorGanapolsky Jan 21 '21 at 21:01