I was wondering in which Android lifecycle function (e.g. onPause, onDestroy) should sqlite database calls be initiated within.
Currently I have a model object that is being manipulated by the user within an activity, and is saved to disk when the app shuts down.
I thought about using onSaveInstanceState, but I realize that its not called during app shutdown (as it doesn't make sense to save state in this scenario)
The documentation says:
You should … use onStop() to perform relatively CPU-intensive shutdown operations. For example, if you can't find a more opportune time to save information to a database, you might do so during onStop(). […]
Related
I currently store my app data for an Activity in a Parcelable object. On orientation change, I save it and load it by using onSaveInstanceState and onRestoreInstanceState.
I want to save the data to the database when the user exits the activity.
And, I want to minimize the database calls. So,
Where should I write the code to save the data to database? Is it onPause(), onResume(), onStop() or onDestroy()?
If you're really talking about best practices, then none of the above.
An Activity is View-tier object. Some might argue that it is a hybrid Controller and View. In either case, it's not a Model or Business-tier object.
If your data is important enough to write to a database, then I'm guessing that it's not view state, it's probably domain data. So, the best practice would be to let the Model/Business tier (which is completely decoupled from the Activity) handle it. And given the nature of mobile apps, I'd write to the database (asynchronously, of course) whenever the data changes, without regards to the lifecycle of the various Android components.
I currently store my app data for an Activity in a Parcelable object
Since the rest of your question is about database I/O, please note that Parcelable has nothing to do with database I/O.
I want to save the data to the database when the user exits the activity.
I would recommend that you save the data when the data changes, rather than wait and risk losing that data (e.g., app crashes).
Is it onPause(), onResume(), onStop() or onDestroy()?
It is not onResume(). That lifecycle method is called as part of activity coming onto the screen, not when the activity is leaving.
It is not onDestroy(), as there is no guarantee that onDestroy() will be called.
Either of the other two are reasonable. The primary difference is visibility:
If an activity takes over the foreground, but that activity is themed like a dialog or otherwise allows your activity to peek through, you are only paused
If an activity takes over the foreground, and your activity is no longer visible, you are paused and then stopped
A correction to the accepted answer: (I am surprised it is Mark Murphy!)
From the android documentation on activity lifecycle:
onPause() execution is very brief and does not necessarily afford
enough time to perform save operations. For this reason,
you should not use onPause() to save application or user
data, make network calls, or execute database transactions;
I know this question has been asked a million times, I myself though that I already knew the answer and that the correct one was that the only guaranteed call is to onPause(), so you should save your data there.
However, in many places of android documentation they always suggest not doing heavy work (such as writing data in database) in the onPause() method as it will delay the transition between the activities.
According to Android Developer Guide in Table 1
onPause(): This method is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, and so on. It should do whatever it does very quickly, because the next activity will not be resumed until it returns.
Killable: YES
Then according to Android Developer Reference Guide in the similar table.
It says the same thing but:
Killable: Pre-HONEYCOMB
And they add a little note that says:
Be aware that these semantics will change slightly between applications targeting platforms starting with HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts when onSaveInstanceState(Bundle) may be called (it may be safely called after onPause() and allows and application to safely wait until onStop() to save persistent state.
Killable
Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may killed by the system at any time without another line of its code being executed.
FOR POST-HONEYCOMB (i dont care about earlier versions):
So, is it OK to assume that any Android device (including different ROMS) will ensure a call to onStop on the activity? And this is the best place to make any time consuming storage writing of the App?
Note: This is extremely confusing as most answers here, sites, books, and even online android tests take as a correct answer that you should save it in onPause and NOT in onStop.
When to save data to database, onPause() or onStop()?
Either. They are nearly identical, particularly on Android 3.0+.
If the activity that is taking over the foreground is a typical full-screen activity, so that the earlier activity is no longer visible, onPause() and onStop() will be called in rapid succession.
If the activity that is taking over the foreground is themed to be more like a dialog, where the earlier activity is still visible, onPause() will be called, but not onStop(), until such time as the activity is no longer visible (e.g., user now presses HOME).
Most apps aren't worried about the "themed to be more like a dialog" scenario, in which case onPause() and onStop() are called one right after the next, and you can fork your background thread to save your data in whichever of those makes sense to you.
However, in many places of android documentation they always suggest not doing heavy work (such as writing data in database) in the onPause() method as it will delay the transition between the activities.
The same is true of onStop(), as both of those methods are called on the main application thread.
So, is it OK to assume that any Android device (including different ROMS) will ensure a call to onStop on the activity?
Both onPause() and onStop() will have the same characteristics from the standpoint of process termination. Either both should be called (normal case) or neither will be called (e.g., you crash, the battery pops out the back of the phone).
And this is the best place to make any time consuming storage writing of the App?
Either onPause() or onStop() are fine places to trigger the work, done on a background thread, to persist your data. If you prefer to do that work in onStop(), you are absolutely welcome to do so. Personally, I'm an onPause() kind of guy.
If you want more safety, storage in onPause.
If your data is so big that you have to storage it for several seconds, you may open a background Service (e.g. IntentService) to save.
You can also check the system version in your code and choose when to save. if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.ICE_CREAM_SANDWICH){}
In most situations this rule of when to save will not be changed by some customed os. But of course there can be some other os which certainly changed it. So the most important thing in android development is that u need to know that everything can be different in different phones.
I know this question is prehistoric, but it seems like people like me still happen to land on this question. So I guess it may make sense to add an answer I found in the documentation, which states:
To save persistent data, such as user preferences or data for a database, you should take appropriate opportunities when your activity is in the foreground. If no such opportunity arises, you should save such data during the onStop() method.
source
But wait, there's more:
Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may be killed by the system at any time without another line of its code being executed. Because of this, you should use the onPause() method to write any persistent data (such as user edits) to storage.
source
So wrapping up, it seems like persisting data onPause() is the best thing to do.
I am trying to read data from the SQLiteDatabase when my application opens, and commit it all by inserting all of the changes when the Application closes. I know this isn't the most efficient, but the assignment I am working on is about UI mostly, not how the back-end works. How can I go about doing this? I tried creating my own Service class, but then I soon discovered that I can't seem to use the constructor for the Service. My goal is to use some kind of onCreate() and onDestroy() functions to work with the database when the App is started/ended.
In the situation like yours, the best approach is to use onPause() as described here:
Note: Because onSaveInstanceState() is not guaranteed to be called, you should use it only to record the transient state of the activity (the state of the UI)—you should never use it to store persistent data. Instead, you should use onPause() to store persistent data (such as data that should be saved to a database) when the user leaves the activity
The documentation suggests that the data should be committed/read in onPause()/onResume().
Yet when the application is no longer in the foreground, its data structures remain intact, which suggests that one could delay committing/reading data until the application is no longer visible, i.e. in onStop()/onStart(). Particularly since onStop() is guaranteed to be called before onDestroy().
Is it perhaps the case that either approach is suitable? Is the documentation giving here merely a guideline?
Update
Suppose your application needed to save relatively substantial data, say edits to a large image. One would then surely not write/read in onPause()/onResume(), lest the user experience become sluggish. One would in that case choose instead to write/read in onStop()/onStart(). Is that true?
The problem with using onStop is that you have no guarantees on when it will be called since the only sure thing is that it will be called before onDestroy. If you wait until onStop to commit your data it may be to late for another activity to show/use any of those changes. Same thing applies to onStart, your activity may not need to be restarted if it was just in the background so you'll have stale data. Using onResume and onPause guarantees that your data will always be current, commits are made as soon as the activity goes to the background and new data is loaded as soon as it becomes visible.
Yes, it is just a guideline (and generally a good one). It is up to you exactly when you want to commit changes. I personally like to create Store Objects that allow a simplification of Databases or SharedPreferences, and when a change is made, I commit those changes immediately. For simple data storage, this will be quick and invisible to the user. For large data sets, this may take more time, and you may wish to make those writes on a time interval, as well as in onPause.
As for when to read - you can read whenever, but again longer reads will often affect the user experience, unless you have taken care of it in another thread, such as with an AsyncTask.
To Further answer your update:
It depends on the developer, however I would write in onPause() and if necessary, read in a separate thread, probably initialized with onResume(). I may also write data out on a scheduled interval using a Timer thread, depending on how it would affect the user experience for the current session, and if it would be catastrophic for the phone to turn off and lose all data before onPause() is called.
The true answer to this is, onPause is the only method you are guaranteed to get called before Android can destroy your process. If a user leaves your app to take a phone call, and Android decides to close your process, its entirely legal for you to only get an onPause call. If you hadn't saved your state there, when the user hits the back button, you will end up recreating your activity in a different state than the user left it in.
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.
You should try AsyncTask, which will block your ui but wont show blank screen, will load the necessary xml elements and then will get call from Async task, in async task save your doc in database.
Follow this link: AyncTask Exmaple