I know that a Bundle can be used to pass data between activities, as well as for saving and restoring data in cases of configuration changes like a screen rotation.
I also read that SharedPreferences is the preferred way to store persistent data, rather than a Bundle.
Why exactly is this the case? In order for a Bundle to handle a configuration change, it would have to persist even after an activity is destroyed. So what exactly is the lifespan of a Bundle? Is there a certain point where it arbitrarily gets eliminated by garbage collection, or does a Bundle's data persist for as long as you don't manually choose to clear it?
Bundle lasts while the Activity exists, aka it has not been finished.
An interesting fact to note is that when process death occurs and Android massacres your application and the Application class is recreated (onCreate() is called), then the Activity stack is reconstructed, and the activity is reinitialized from the saveInstanceState bundle.
The SharedPreferences literally stores the data you give it in an XML file in the data/<applicationname>/preferences folder, if I remember the location right.
SharedPreferences are for simple persistent settings storage. Like the home page on a Browser that should be available every time the user opens the app. These are just key:value pairs designed to hold simple things.
Bundle is a way of storing data to either pass to another Context (another Activity, Service, etc) or to save and restore your own current state in onSaveInstanceState and onRestoreInstance state. This data is NOT persistent and used while the application is in use.
Related
I have a singleton that contains some data that I want to hold globally for the app.
I know that if the user has navigated away from my app, and if the system needs resources it will kill my app (or just the activity, not sure). Then if the user opens my app again, it will restore the activity and wil have save the local activity variables automatically.
Will this process also restore the static variables that were set in my global singleton class out side of the activity?
No. Only what is in your saved instance state Bundle might be restored if Android terminates your process, and then only if the user returns to your app relatively quickly (say, within 30 minutes).
The saved instance state Bundle is mostly for "in flight" data (e.g., partially-filled-out forms) that you would not mind losing if the user does not return to you for a while. For anything else, save the data yourself, whether to local storage or "the cloud".
If you want to save the state of that variable you can either save that in sharedpreference in your onPause method of an activity and then retrieving that variable again in your onResume method
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
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.
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.
The description of Android Bundle says:
Bundles are Android's way of maintaining and passing program state. The system is constructed around the assumption that any program (characterized by a collection of activities) may be preempted at any time, and if the system resources are low, may be subsequently killed. To handle this difficulty, a Bundle called an icicle is saved whenever the activity is preempted.
Like with a hash table or dictionary, items added to the Bundle are given a key which is later used to retrieve the data (using data-type specific methods like getCharacter(String key) and getParcelable(String key)). When you are creating activities, be sure to save any important state information into the icicle given to onFreeze so that you can restore your program in onCreate if it is killed while suspended.
Is Bundle the same as Session[] in .NET?
Not exactly, no.
In .NET the you can access the State object from anywhere at any time, and you will be pretty sure that objects that you have placed inside of it will still be there when you are calling it. The session expires though, and unless you have saved anything in your viewstate, that data becomes lost.
Android uses Bundles because of the nature of the OS, it will keep your application "alive" in the background where state is preserved, but if it deems that your application is idle and that it can be killed, it will kill your app to free up resources. Before your app process is killed it will call onFreeze() (now renamed to onSaveInstanceState()) which will give you the opportunity to save data to the Bundle that will be passed to onCreate the next time your application starts up (so you can initialize your screen again).