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.
Related
So, as far as I have understood, once the App is not destroyed and is in the background; if the OS requires more memory the OS kills the app but saves the state (onSaveInstanceState). And when we re-open the app, it would seem like we are facing our previous activity but it actually has been destroyed and created again. If my interpretation is correct, how does the App retrieve the saved state? Does it store it in memory? For how long are we able to retrieve the saved state?
If my interpretation is correct, how does the App retrieve the saved
state?
From the Android documentation
If the system destroys the activity due to system constraints (such as
a configuration change or memory pressure), then although the actual
Activity instance is gone, the system remembers that it existed. If
the user attempts to navigate back to the activity, the system creates
a new instance of that activity using a set of saved data that
describes the state of the activity when it was destroyed.
Regarding your second question - it's the implementation detail how the OS does it and it's actually shouldn't worry us :). What's important is that it should do it reliably.
The system will keep the saved state as long as the user doesn't press Back or finish() of your Activity is not called.
The OS stores it. It calls onSaveInstanceState to let you generate a Bundle it stores, and will call onRestoreInstanceState to let you restore yourself from the state. How the OS stores it doesn't matter- maybe it saves it in RAM, maybe it serializes it to disk. What is assured is that if you go back to that activity you will be passed a Bundle object with the information you previously filled in. You do not need to retrieve the state- if it exists it will be passed to you.
I've implemented onSaveInstanceState and onRestoreInstanceState in my android activity.
These seem to work OK, but I'd like to explicitly save the instance state when certain things happen (e.g. when the user presses a button) in case the application crashes, or I terminate it via the debugger
I can call the method obviously, but that doesn't provide the correct Bundle or anything else.
I've looked around, but I can't see any way to do this. Is it possible?
If not, can anyone offer a decent solution for saving activity state at specific points in case of crash/termination?
Thanks
Bundles are only stored in memory, which means even if you manage to put the data into the Bundle it will be gone if your app crashes.
I'd suggest you to use onSaveInstanceState for what it's designed for - restoring Activity state within an active process. If you want to persist some information so it won't get lost if the app crashes you should use one of the persistent storage options.
Ideally you would have model class for the data that you are displaying. You can persist the model using SQLite and some DAO library. When you do that you can then restore from the database in onCreate of your Activity.
Depending on complexity of the information you can also choose Shared Preferences. If you have only a few key value pairs this is a good choice and you don't have to use models.
I have implemented onRestoreInstanceState and onSaveInstanceState. They both work successfully when the app is minimized (by pressing the home button, or another activity is in the foreground). However, when I minimize the app and the kill the process (by opening the list of current processes and ending that one) the app does not restore the saved instance state. How can I make it restore that saved state? Is my best option to write the savedInstanceState bundle to a file using serializable (thus having something stored that on the hard drive, rather then RAM), then reload the savedInstanceState from the file?
How can I make it restore that saved state?
You can't. That's not what the saved instance state is for.
Is my best option to write the savedInstanceState bundle to a file using serializable (thus having something stored that on the hard drive, rather then RAM), then reload the savedInstanceState from the file?
Your "best option" is persistence, such as a file, database, or SharedPreferences. Your specific approach seems odd.
Saved instance state is only for temporary information, such as the contents of a form that the user has filled in but not yet submitted. Anything beyond that does not belong in saved instance state, but rather in some sort of persistent data model. This is no different than building a Web app, where the data that you have in your DOM and JavaScript variables are not going to live forever, but instead need to be store somewhere (typically on a Web server).
It's probably too late for the answer, but you can save state (and it will survive the process killing) with SavedStateHandle from Android Jetpack.
See more here:
https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate
I want to save some small data structures (~1kB total), as well as the user's preferences, while my app is closed. The settings are modified only in my PreferenceActivity, but the data structures are modified in pretty much every activity. I've extended Application and made all the data structures and preferences static. I've then tried saving to SharedPreferences in my application class's onTerminate() and loading it again in onCreate(). However, onTerminate()'s documentation states that "It will never be called on a production Android device, where processes are removed by simply killing them".
Answers to this question suggest saving to SharedPreferences in the onStop() method of each activity modifying their data. Will this guarantee that the data is saved in all cases? Is there a way to avoid the waste of saving every time the user transitions between activities (or should I even care)?
I would honestly just save in the onPause() of each activity as is recommended by Android (i.e. when you write an email notice how the draft is saved when the app pauses, such as if the screen turns off). Unless you notice that it is causing lags/delays, it probably won't matter too much.
If you do notice lags with this "autosave" method, then you should probably have some sort of "Save" functionality implemented in each activity, which could, for example, entail using a ProgressDialog / AsyncTask combination.
I would like to know where the bundle "outState" of the method onSaveInstanceState(Bundle outState) is stored.
Is it stored in memory or in the device storage?
I am concerned about the security of the data which is stored in the bundle.
To store data only for application lifetime (ie temporarily), use the onSaveInstanceState(Bundle) activity event
This data will only be held in memory until the application is closed, the data will be available any time that this activity starts within the current lifetime of the application.
Explanation: if data is stored here by activity A then the application shows a different activity or rotates the screen (hence closing A) and then returns to A the data can be retrieved to populate the controls. However if the application is closed and opened again the data will be gone and the controls will revert to their default values.
Example of use: storing text typed in by user and selections making up an order, blog entry, message, etc...
Note:
It’s important to notice that only the Activity is destroyed and recreated, not your whole application! An Android application can consist of many Activities, Services and ContentProviders! If the application is closed (for example by pressing the “Back” Button, then all values will be gone. savedInstaceState is only there to preserve data temporary when an Activity is destroyed/recreated, not the application itself.
If you want to preserve data permanently, you need to save it either as Preferences or in a ContentProvider/database.
Here is a detailed answer for where the outState Bundle data is saved:
...Bundles are an IPC mechanism, so it's not going to the filesystem. But now there's a P involved – which process is it? And what is that process doing with this data? And do I need to be worried about it? It turns out that these instance state bundles are stored in the Activity Manager service. This service is implemented under the package com.android.server.am in the Android source code. Recall that Activities are stacked one on top of another and that Android calls these stacks “Tasks”... Each of these tasks is represented internally with an object of class TaskRecord. This class contains an array of ActivityRecord objects, each of which manages the state of an Activity. ActivityRecord contains a member of type Bundle named icicle. This icicle-bundle is the saved instance state and it is actually stored in the memory space of the Activity Manager service.
Source: https://www.linkedin.com/pulse/android-onsaveinstancestate-bundle-secret-safe-daniel-pietsch/
The documentation has been updated and indicates precisely that the state is serialized to disk:
Saved instance state bundles persist both configuration changes and process death, but are limited by amount of storage and speed because onSavedInstanceState() serializes data to disk.
You can also found a table comparing the differents approches to preserving UI state
Source: https://developer.android.com/topic/libraries/architecture/saving-states
I don't think there's any way that any malicious background process can get at the bundle data of your application. It is not documented how Android treats the Bundle data. It may or may not be written to disk in the event that your app is cleaned, while backgrounded. However, given that we don't know whether or not this data is saved to disk, and if it is, given that we have no clue where, and almost certainly don't have read access to that part of the disk, I wouldn't worry about some third party process being able to recover that data.
Consequently I'm not clear what you might think the exposure is. Though I may be missing something.
However, in answer to your question, it is absolutely in memory while your app is alive, and if your app is backgrounded it may or may not be written somewhere hidden, but we dont' know because Google hasn't told us.
It's destroyed along with the application when the memory is collected.
My guess would be in memory, but the best way to protect your data would be not to trust the system and encrypt it. Never trust the client (in this case the client being the OS).
EDIT:
To be clear, I'm not saying encrypt the bundle. Rather I'm saying that any sensitive data should not be put into the bundle. If you must put custom data in the bundle, then encrypt it.
But ultimately you should keep as little sensitive data on the client as possible. This is the same reason a e-commerce site would only show the last 4 digits of a credit card.