Thorsten Dittmar Thorsten Dittmar - 1 month ago 14
Android Question

Should I persist data objects in onSaveInstanceState

I'm using greenDAO in my android app to display a list of objects in a

RecyclerView
. I have a subclass of
RecyclerView.Adapter
that takes a list of objects which are greenDAO entities.

What I do in
onCreate
is:


  1. Create an instance of my adapater passing
    null
    for my list. This is just to make the adapter known to the
    RecyclerView
    below.

  2. Initialize the
    RecyclerView
    with layout and adapter.

  3. Call a method that asynchronously queries the data using greenDAO and upon success updates the adapter with the actual list of objects so they are displayed.



This is the relevant code:

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

...

mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mListAdapter = new MyRecyclerAdapter(null);
mList.setHasFixedSize(true);
mList.setLayoutManager(mLayoutManager);
mList.setAdapter(mListAdapter);
refreshItems();
}

public void refreshItems()
{
AsyncSession asyncSession = ((App)getApplication()).getDaoSession().startAsyncSession();
asyncSession.setListenerMainThread(new AsyncOperationListener()
{
@Override
public void onAsyncOperationCompleted(final AsyncOperation operation)
{
if (operation.isCompletedSucessfully())
mListAdapter.setItems((List<Item>) operation.getResult());
}
});

asyncSession.loadAll(Item.class);
}


This works pretty well. Now I noticed, that of course the method that queries the database via greenDAO is invoked every time I rotate the activity or come back to it from another activity. That's pretty clear, since I'm calling that method from
onCreate
.

My question is: is it best practice to do this like I'm doing it (requery DAO every time) or should I make my objects parcelable and save the list I have in
onSaveInstanceState
and restore it in
onRestore
instead of requerying DAO?

Answer

What you're doing is completely valid and you don't need to save the queried data in onSaveInstanceState(), use in-memory cache, or any other optimization (even if GreenDAO wouldn't have internal cache).

In fact, you're more than all-right because you perform the query asynchronously - GreenDAO's creators kind of claim that the queries can be executed on UI thread in most cases (which I find hard to agree with).

I would also suggest that you perform data query in onStart() instead of onCreate(). I personally think that onCreate() should be used only for operations you would otherwise perform in the constructor (e.g. fields initializations). Another reason to perform this query in onStart() is that if the user leaves your application for a long time and then gets back to it, the data might get outdated (e.g. due to background syncs by SyncAdapter) and you'll want to refresh it.

The last piece that you might want to add is "data change notifications". You will want this mechanism to be in place if the data that you query and display to the user can change without user's interaction (e.g. due to background syncs by SyncAdapter). The concept is simple - Activity registers for notifications about data change in onCreate(), and if notification received you perform re-query in order to make sure that the user sees an up-to-date data.

I can't claim that the above are "best practices", but they are good practices that work well.

Lazy list:

As @pskink suggested in his comment, you could also employ LazyList. Be aware, though, that it doesn't obviate a need for async query of data. Usage of LazyList allows you to perform the query as usual, but load the results into memory in on-demand way. This might be useful if you expect the query to produce lots of data.

In my opinion, however, one should optimize the code only if actual performance problem is being observed. So, unless you know ahead of time that a particular query produces thousands of results, I say you don't need LazyList.