In my application I'm storing all data in ApplicationData so that it can be easily shared between activities. My understanding is that this data should persist for the full life cycle of the application from the initial onCreate to the final onDestroy. That being the case, is there any need for me to store data in persistent storage during the onPause of all but the top activity?
My understanding is that this data should persist for the full life cycle of the application from the initial onCreate to the final onDestroy.
Not exactly. Your process and custom Application class will remain around as long as Android lets it. Android may terminate the process outright to free up memory in an emergency. Not to mention that battery-powered devices may have their batteries go dead.
That being the case, is there any need for me to store data in persistent storage during the onPause of all but the top activity?
Only if you don't want the data. Use Application (or static data members) as a cache only.
Related
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;
I want to keep some objects in memory for operations in all the activities of my app and I also want to store those objects when the app closes. Which is the most efficient way of doing this ? Some possibilities that I can think of are:
1) Keeping local copies of objects in all the activities, serialize them and pass them through intent.
2) Keep local copies of objects in all the activities, serialize them and do file read and write on activity resume and pause respectively.
3) Make them static variables but I don't know when to do the file read/write operations in that case? This approach may leak memory.
4) Use Application object and define my objects as variables in that object. Since it has a definite life cycle like activity, I can do read/write accordingly.
I recommend your approach number 2. The reason is that there is no such thing as "the app closes". Android tries to keep it in memory until the memory is needed for other purposes. The process of your app is then simply killed, you don't get any callbacks called.
Singletons or the Application object can be used to cache the objects if you are careful to load and store them as necessary. However, this also means, that the memory used for them is only reclaimed if the app process terminates.
It depends on your data. All approaches are good in some cases.
I think you have 2 options:
keep data in sqlite. It is easier then files and faster. When activity starts request required data from db and show it. (use files if you really want)
create a singletone class to store data. Data will be loaded in memory and you can access it very fast. When data changes save it to sqlite or file. google "share data between activities"
Is there any way to avoid static data loss in Android if device is kept idle ?
I am having static object which will store some values from activity UI.
If device is kept idle for 4-5 hours that static object will be removed to use memory for other running applications.
If I am doing it wrong, is there any other way to avoid this ?
You can't avoid it. Android can kill your process at any time and does not guarantee to call you back.
This only happens if your app goes to the background. Save your data in onPause() and reload it in onResume(). See the Android documentation for Activity lifecycle for more information.
No, that's how Android is meant to work.
Simply, if data are meant to be persistent, ie if its lifecycle spans beyond the one of the Activity which created it, save it on a persistent storage (ie internal memory), in a flat file or in a database depending if the data has an inner structure or not.
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.