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.
Related
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.
Now I'm facing some problem in Android when memory is low or the application is killed by system.
Scenario 1:
I set some static members in a class, I found in some situation , it will be deleted by system when the application is still running.
My problem to this is : when does this kind of GC run?
Scenario 2:
If I switch to another large application and then switch back to my application ( named App_A). App_A sometimes will be recycled by system and restart the last activity when it be switched back.
But there are some application-wide data (like login info) I saved in a singleton.
My problem to this is : Dose the application-wide data saved in singleton will be deleted?
If so, is there a appropriate way to restore the data?
My effort is:
To Scenario 1, I will avoid to use static member directly.
To Scenario 2, I will save those data into file , after it be deleted, I pass Context to each public function to let each of them have the ability to restore the data. But I think it will be unfriendly when the function is used in some situation which need run quickly.
I can only answer about Scenario 2.
Android will try to keep recently used apps in memory, but if the user switches to another app and memory starts running low, the OS has the option to kill the recently used app to make more memory available to running applications.
I had the same problem, where I had some user-context data like username in a static singleton. This data would disappear when returning to the app after using a number of other apps.
The way I solved this problem was to use the activity's intent. Since the user data was retrieved at the beginning of the app, I would simply pass this data to subsequent activities in their intents. Because the OS stores the intent and uses it to recreate an activity not in memory, my data was no longer vulnerable to being garbage-collected.
Also consider other means of persisting data: Shared Preferences, file system, SQLite database. But never count on static data from previous execution being available at the start of an activity.
It is generally bad idea to use singleton to save some data.
Best practice is using any persistent storage - SQLite, Realm,JSON, or any file.
Easiest way is saving your login data for ex. in JSON - then in Application class parse it in onCreate method into POJO - then you can get it from any place of your app. And store to file when app is closing or on any change.
Anyway I suggest you to read Android guides about persistence, memory management and performance tips.
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.
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).