Android: How can I save application wide instance state? - android

Regarding application wide state, I have read many discussions about POJO Singletons vs. subclassing Application class.
Regarding saving state, I've learned about Activity.onSaveInstanceState.
But since Application doesn't really have Lifecycle methods, how can I save state which is used from several Activities?
My first idea was to use onCreate() and onSaveInstanceState() in my main Activity, but what happens if user pauses app while being in another Activity? When the app comes back to front, only this activity, but not my main activity will be recreated, right?
Will I have to do the same onSaveInstanceState and onCreate in ALL my activites or is there another way?

how can I save state which is used from several Activities?
Update your persistent store when the data changes. There is no "instance state" that is "used from several Activities", by definition.
My first idea was to use onCreate() and onSaveInstanceState() in my main Activity, but what happens if user pauses app while being in another Activity?
Eventually, your process gets terminated. "Instance state" (e.g., onSaveInstanceState()) may be supplied back to you again later, depending on circumstances. Anything you absolutely need to hold onto needs to be put into a persistent store (database, SharedPreferences, file), usually at the time that data is changed, much like how software has been written for the past 60 years.

Related

Best Practice - Saving Activity data to android database

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;

How to save state of activity on android on back key press

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.

Persisting state in the android Application class

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.

android save session state across activities

What is the best way to maintain session information across multiple activities?
The question What is the best practices on Android to keep data between activities deathes/restarts for the whole application session? has some ideas, but does not really help me.
*My application has multiple activities with the manifest tag singleTop. They essentially work as different tabs - they each maintain their own set of fragments and back stack and so putting it all into one activity would break navigation for the user.
I am currently saving the session data as a static singleton created by my Application subclass. This works fine most of the time, except when the entire application is killed by the OS to save memory (as mentioned in the above link), say, when the user gets a call on a device with low RAM.
The only notification the app has that it is going to be killed (as far as I know) is
Activity.onSaveInstanceState(Bundle outState)
So the problem is this: onSaveInstanceState will eventually be called on every activity, not just the top-most one (the one that will appear when the user eventually returns to my app). When each non-top activity resumes, I could use Activity.onRestoreInstanceState(Bundle savedInstanceState) to restore my singleton session, but non-top activities would have old copies of the data (they may have been navigated-away from long before the user got the call).
One solution would be to only restore data to the singleton session Only if it is currently empty, but this relies on the first activity to receive Activity.onRestoreInstanceState being the top activity. This is not always the case - if the user gets a call and then returns to the app via the launcher icon, then the Main activity will be resumed first and brought forward, not the activity the user was on when they got the call.
A simple notification in the Application class that the application is being killed by the OS (not the user) is really what I need - I would then save the session to a file, and read it back on the first call to Activity.onRestoreInstanceState, but AFAIK this doesn't exist.
If you have some data that you want to store when app closes and reload them when app starts, you can have a mechanism to store and retrieve them on application's shutdown and startup. To do this override onStop() and onStart() methods on Activity's lifecycle.
And I think the best way to store and retrieve data in these two methods is SharedPreferences.
I would simply insist to use Application class to save the session. Using Application class you will be able to access the session everywhere were you are having Context so probably you can access in your whole Application. Application class also maintains the value after you Application is closed so its better to clear previous session when your Application is re-launched.
As the main use of Application class is to maintain global state of variables so that they can be used throughout the Application with updated values.

Are the bundles in android permanent in saving activity states ?

When I want to save some state behavior of the activity, The docs says that we should implement OnSaveInstanceState and OnReceiveInstanceState.
They say that this will save the activity state even after destroy or restarts. I care more about destroy (the activity is completely gone) , does that mean the bundles are considered persistent ?
when I open a pdf reader, clost it and open it again i see that it opens in the same page I was in. is this implemented using Bundles or oth
To store persistent application data use Shared Preferences. Shared Preferences are simply sets of data values that are stored persistently. By persistence, we are talking about data that persists across application lifecycle events. In other words, the application (or device, for that matter) can be started and stopped without losing the data. The next time the user launches the application, that data will still be available.
Some Games use Shared preference for exemple to store the level of the game reached, the player's name ...
see this link to learn how to use Android Preference API
Preference are simular to bundles However they are persistant and bundle are not!!
Keep in mind that if you need to store persistent data you have 4 options to do this:
Using Shared Preferences
Using SQLite Databases
Using Internal Storage
Using External Storage
Bundles are not persistent, the documentation says not to count on it, onSaveInstanceState() is called when the activity is about to be killed by the system, but for a known restart (for
instance on a screen rotation.) If your activity is killed because the system needs more resources (while the
activity is in the background), onSaveInstanceState() will not be called, but onPause() will. onSaveInstanceState()
really is not meant to save persistent data, as the doc states.
You can sorta consider SavedInstanceState() permanent but it's not recommended to use it for saving application related data in a persistent manner as It's not guaranteed to be called and it's not recommended by the authors themselves.
so, Only use them for saving user interface state changes (background color, currently selected items ,..) and use other method for persistence like : SharedPreferences, Files and SQLite.
Bundles are not persistent, and the documentation for them specifies that using them for persistence is not a good idea as their internal format may change between devices or even OS versions.
SharedPreferences, on the other hand, can be persisted and are the recommended way to store information like current app state.
Some relevant parts from SavingActivityState
:
Note: There's no guarantee that onSaveInstanceState() will be called before your activity is destroyed, because there are cases in which it won't be necessary to save the state (such as when the user leaves your activity using the Back button, because the user is explicitly closing the activity).
There is no guarantee data will be stored, especially in the case where your user exits the app.
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.
So like K-ballo said, used SharedPreferences if you have persistent data to store. onSavedInstanceState() is mostly useful for storing UI related data.
As every one else has recommended use shared preference and you should do this saving in onDestroy and onSavedInstance both.
When android is going to run low on memory, its just going to kill your application and call your onSavedInstance without calling onDestroy etc. Save your context in bundle it passes in onSavedInstance. When your app comes in foreground again, android will take care of restoring your back stack of activities. But this time it will pass you the bundle in your onCreate for each activity which will have all the values you saved in your onSavedInstance while your app was getting killed.
Hope this helps.
Short answer: It's not permanent.
Long answer: From "Android Programming - The Big Nerd Ranch Guide":
When onSaveInstanceState(...) is called, the data is saved to the
Bundle object. That Bundle object is then stuffed into your activity’s
activity record by the OS
...
So when does the activity record get snuffed? When the user presses
the Back button, your activity really gets destroyed, once and for
all. At that point, your activity record is discarded. Activity
records are also typically discarded on reboot and may also be
discarded if they are not used for a long time.

Categories

Resources