When a user manually kills an app, what data is cleared?
I have a bit of functionality that only properly clears the data on app kill and reopen, so clearly the system is clearing some data that I am missing.
Basically, I want to know what sort of delete/clear data is called programatically so that I can try and figure out what is being kept around on close/reopen that doesn't stick around for kill/reopen.
EDIT: I am basically trying to find out the difference between finish() of an activity that contains a webview and force-close/reopen
When you force close, the app will be completely removed from the memory. For example, all services will be closed, any static variables that you might be holding, everything will be cleared. However, persistent storage such as SharedPreferences will not be affected. Every value that was committed before the force closure of the app will be remain as they were.
Also, you cannot expect the lifecycle methods to be called on Force Close. So if you're doing anything inside onDestroy of a Service or an Activity, that'll most likely fail since the method is never called.
Related
I recently wrote a demo app, which just needed to display some data temporarily --- I meant for the data to disappear once the app was properly destroyed by the user. Toward this, I read the page
The Activity Lifecycle , which seems to recommend overriding the Activity methods
onRestoreInstanceState() and onSaveInstanceState().
It worked great! The data was preserved through screen rotations, and sending the app to the background.
But then I would leave the app running and walk away, and when I looked at it again, the data was gone.
I spent hours trying to de-bug my app, and re-reading that page.
Finally, I read
Saving UI States. It refers to overriding these methods as "ViewModel" approach, and explicitly states that data saved this way does not survive system-initiated process death --- which explains my observation.
My main question is: what on earth is the practical application of this "ViewModel" persistence approach? What is the use-case for a persistence mechanism that randomly disposes of data when the user isn't looking?
(I guess this is an old API left over from the times when apps didn't run in the background. But I don't see that reflected in the documentation.)
A second question is, reading the first page, how on earth was I supposed to understand this unfortunate behavior? Did I miss something? (It is very long.)
what on earth is the practical application of this "ViewModel" persistence approach?
It is not a persistence approach. A ViewModel is a way of holding onto state across configuration changes. Using a SavedStateHandle with ViewModel — which maps to onSaveInstanceState() and onRestoreInstanceState() — is also useful for a fairly narrow use case:
User is in your app and does something that you don't want to save to disk or the server (e.g., the user didn't click "Save" yet)
User turns off their phone screen or switches to another app (e.g., via system HOME navigation or the overview screen)
Time passes
Android terminates your app process to free up system RAM for other apps
Within ~30 minutes of having left your app, the user returns to your app
At this point, Android wants to pretend that your app had been around all along, despite the fact that your process had been terminated. So, Android will not only start up a fresh process for you, but it will recreate the last activity the user had been on... and you get your saved instance state back as part of this.
However, this is not a persistence approach. For data you want to have survive long term, you need to save it to disk (SQLite, SharedPreferences, JSON file, etc.) or to some server. Notably, if the user leaves your app for an extended period (over ~30 minutes), Android will not attempt to restore the instance state, and your app will be started normally.
You need to use a SavedStateHandle with a ViewModel to get data persistence when the system terminates your app in the background. Otherwise it's more about sharing data between components, and surviving Activity destruction e.g. on screen rotation without having to do a lot of boilerplate handling.
Just like with onSaveInstanceState, this is purely about persisting data when the system kills your running app to recover memory, so that when the user switches to the "running" app again, it can be recreated and restored exactly as it was. It doesn't save any data when the app is intentionally stopped, e.g. calling finish(), the user backing out or swiping it away etc.
This stuff should always just work - if you were seeing your data "go missing" and the app wasn't crashing in the background, it's possible your save/restore logic wasn't working. A good way to test that is going to Developer Options on your device (if you don't know how to get that do a search, it depends on your device) and enable Don't keep Activities. That will destroy them as soon as they go to the background and it should help you test how that's handled. The fact you were handling rotations ok suggests it was a background crash though, but that depends on how you were handling configuration changes
I'm having an issue with an android app I'm writing that seems like it should be a common issue but I can't find any information on it.
I have a scoreboard activity in my app that just stores a grid of scores in textviews, it's the kind of thing that the user will update, then hit the back key and look at some other activities, then come back later to update it, leave again, etc...
The problem is that every time they leave and come back the whole activity gets reset, losing all their scores. I can't use saveInstanceState because it isn't called on back key pressed. I really don't know where to go from here except for saving thew hole grid in sharedpreferences, I feel like there has got to be a better way though
Any ideas?
In general, you need to save any state information in onPause(), and recover it in onResume().
I was under the impression that various state information is kept automatically when you close the App, and automatically restores itself when start it back up again (until Android removes the App from its memory to make space, calling onDestroy()).
If I were you, I would store the grid in SharedPreference. It really is the most reliable solution.
You can also use the details in this topic:
https://stackoverflow.com/a/151940/503508
May this help you
When the user presses the BACK button, your foreground activity is destroyed. That activity will be called with onPause(), onStop(), and onDestroy(). That activity object will then be garbage collected (unless you introduced a memory leak).
onSaveInstanceState() will be called periodically if there is a chance that the activity will be destroyed shortly but in a way where the user might be able to navigate back to it. The prominent case for this is during a configuration change, such as rotating the screen.
What you should be doing in onPause(), if anything, is persisting data using "sqlite, file saving and other persistance methods". Once onPause() is called, there are no guarantees that this activity will stick around, or that your entire process will stick around. Anything you value, therefore, should get written out to persistent storage.
The "state" for onSaveInstanceState() would be things that affect the activity's UI but are not part of the persistent data model. Much of this is handled for you automatically by Android's built-in implementation of that method (e.g., the text in an EditText), but you can add your own information to the Bundle if you wish. However, your instance state is not your data model, so anything you want to stick around needs to be written out to persistent storage.
I am developing an Android application consisting of over 10 activities. I have some state objects that I access in almost every activity and for this purpose these were implemented as global static variables in the MyApplication class.
I noticed that this approach is OK as long as the user is "in" the application. However, when he presses the home button and opens another apps and then goes back to my app through the "Recent activities" button, I see that the Android system resets the statics from the MyApplication so I have to deal with NullPointerExceptions. I know that this behaviour is caused by Android killing and recreating the application process.
I know that the best way to persist this kind of data is using SharedPreferences or SQLite, and I have no problem checking if MyState==null in the onCreate for and restoring it, but the problem is that I don't know when to properly store my state object (in prefs or database). I tried to override MyApplication's finalize() - no good, I saw that onLowMemory may not be called, I don't see how can I use onPause, OnStop and so on because I have so many activities that the serialization de-serialization would considerably slow down the app.
Any thoughts?
Thanks in advance!
It is better to not depend on the Application class unless you need to load some data, before anything else is started. Android can kill your process at any time to free resources, so your app should be able to handle this. Save all of your data in a snigleton class, and load it lazily -- check for null, and if so load on first access. It the state needs to be persistent, consider staving it file/shared prefs. If not, your app can probably live without it, so just make sure you check for null, etc.
Generally, you should persist state when activities become inactive -- onStop(), onPause(), but you can save as soon as it makes sense (e.g., the user has entered all required data). Spin off an AsyncTask to save data in the background and let the user continue their work.
I have a rather small amount of state in my Android app that I wish to ensure is saved persistently. It's tiny, clocking in at about 50 characters.
Looking at the Android Storage Options page, they give a few choices, the simplest which seems to be shared preferences. Now these aren't actually application preferences, more a short indication of where the application is at.
My worry is that preferences are expected to change infrequently and the likely use case may not therefore handle a lot of changes. By a lot, I mean peaking at about once per second, depending on user activity.
So I want to make sure of two things.
The first is that the sample code on that page linked above has the preferences being written out in the onStop method. Are we guaranteed that this will run when the application exits, no matter what?
If so, I can maintain the state in-memory and use it to save persistently, then this frequency-of-updates problem disappears.
Basically, I want to ensure there's no way my application can stop without having saved its state (short of catastrophic failure of course).
Otherwise, I'd rather save this state whenever it changes so as not to lose anything.
Second, and this is important only if I have to save state every time it changes, are there any downsides to saving preferences up to once per second? As mentioned, I'm not sure if it's designed for frequent updates.
If the application exits normally, onStop() is called. If the application is backgrounded (ie with the home button/getting called) onPause() is called, which calls onStop(). If the application exits (ie with the back button), onPause() is called, which calls onStop(), which calles onDestroy(). However, when the application crashes (ie through a nullpointerException, onStop() is not called, the application just crashes).
Personally, I mostly use a settingsContainerObject of some sort, and just write my preferences to the internal storage in the onStop() method. Works pretty well.
In short: yes, onStop() is always called when the application is backgrounded or exit.
You can also stop the application in try/catch blocks, to always save your settings.
On the first time my app is running, on the root activity, the user is required to select a certain options that determines which data would be downloaded for him from a database.
Once he had picked that option, the data is downloaded and kept on a singleton class that should hold that data as long as the application is running. (Even in the background)
My problem is that sometimes after the user exits my application for a while (using the home button), Android apparently kills some of the activities in my app, and somehow with them, it resets the important singleton class. Causing my app to receive all kinds of null reference exception once I try to access the data that is supposed to be kept on the singleton.
I understand that the Android OS can sometimes choose to kill an application, but allow the user to return to it from his last visited activity. Sometimes it just kills the whole application and forces the user to begin from the start.
I was looking for a solution, and I found out about "android:alwaysRetainTaskState" attribute that I can apply on my root activity. Apparently with it, whenever android decides to kill my app, it would at least force the user to begin from the first activity where I can re-download the data, instead of allowing the user to begin with a more advanced activity causing him to get null exceptions.
However when I applied it on my application it did not work, and when I returned to my application I was beginning from an advanced activity, with an empty singleton instance.
I also tried "android:clearTaskOnLaunch" and it worked, but it's an overkill, since I don't want that every time the user would return to the app, he would have to start over. I want it to happen only if android decided to kill the app.
Is there something I'm doing wrong? Is there any chance maybe there's a better solution for keeping the singleton alive?
Thanks!
Nope. There is not better solution. This is how it works. Android can kill your application's process whenever it wants to (as long as it is in the background). You can keep data in a singleton, but it is always possible that Android kills your process anyway. When the user returns to your application Android will create a new process and then create a new instance of the activity that the user is resuming. You need to put code in onCreate() of all your activities that recognizes that your singleton is gone and then does an appropriate thing (either redirects to the root activity of your application or reinitializes your singleton.
It is pretty easy to tell if your process has been killed and recreated. Just add a static boolean variable to your singleton that you set to true when it has initialized. In onCreate() of all your activities, check the state of that variable and do something intelligent if the variable is false.