I'm working on my first Android app. It has a model that is persisted to a database as the user makes updates.
When onSaveInsanceState
is called, I want to save an id that can be used to load the document the user was working on from the database. But this can only happen once the document has fully hit the database. In some cases, persisting a complex document can take several seconds (I'm hoping this will speed up once I take all the verbose logging out, and in actual use a complex document will be built up by the user in stages, each of which will be persisted to the database, so it's not very likely for a complex document to have to all be saved in one go).
Now, the #1 rule of threading on Android is "don't block the UI thread", so of course the DB interactions happen on a separate thread. But my understanding of the Android lifecycle is that in many cases onSaveInstanceState is being called because the Android system wants to kill the process. That suggests I can't allow this method to return until the DB thread finishes saving the document (and in fact with my current design, I don't actually know what the id number of the document is until it's been saved to the DB, so I can't even put that in the bundle of saved state).
Is it appropriate under these circumstances to block the UI thread waiting for the persist task to be done? When onSaveInstanceState
is called because the process is being killed, the app is no longer visible in the foreground, so there's no interface to become unresponsive.
But onSaveInstanceState
is also called when the Activity instance is being trashed by a config update, which happens when the screen orientation changes. It's very unfortunate when rotating the screen sideways fails to do anything for several seconds. In this case the process (and therefore memory space) is still around, so I don't strictly need to ensure the document hits the database, if I can just store a reference to it in the Bundle instead of its id. But I'm not aware of a way to tell the difference between these two cases.
Is there an accepted practice for these situations? Should I just block the thread to be safe? Can I just use normal Java thread primitives to block and wait? Is there something I can do that doesn't block the thread but ensures the persist task will be finished before Android closes the process?
All this also applies to onPause
, as onSaveInstanceState
isn't necessarily going to be called.
You don't have to do to the persistent saving in onSaveInstanceState
, you can pretty much just save the instance state in the Bundle
so that the instance can be quickly resumed in onRestoreInstanceState
.
The Documentation states that you should write crucial persistent data (such as user edits) to storage in onPause
, but it also states that it should be fast so that the next activity can start doing whatever it is it wants to do.
I think my recommendation here would be to just save the document text and whatever in the Bundle in onSaveInstanceState
and restore it in onRestoreInstanceState
. Use onPause
to save a "backup copy" somewhere fast (temporary file maybe?) which can then be restored in onResume
if it hasn't been saved to the database. And use onStop
(which is called when the activity is already in the background) to actually save the data to the database.
Note that the activity might get killed after onPause
has been called (never before, unless the system has very very few resources left...), that's why I would save a quick backup before trying to commit it in the database.
Edit - Extra based on comments
To make sure the background thread that's doing the saving process is done saving before the application can be killed by the system, I think it's fine to block and wait for the saving thread to complete before returning from onPause
but I recommend using android:configChanges="orientation"
to prevent activity restart (and onPause
call) when the orientation changes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With