Taking photos using system provided component(MediaStore.ACTION_IMAGE_CAPTURE) is quit common.
As Ive experimented, with a certain rate the android system will kill the snapshot calling Activity to prevent memory related exception, and the calling activity will be created again where returned. Thus I have to save the states of the calling Activity via onSaveInstanceState, and retrieve them via onRestoreInstanceState. (If Im not correct and there is further info, please point it out)
However, I also found out that, when the killing occurs, all my information stored in the RAM were ERASED, RESETED, for example those Singleton class type objects, or static classes and their fields!
This mechanism is so frustrating, how to handle such situation??
I`ve found it out...
Some android OS kill the snapshot calling Activity to avoid memory related exception. So, I have to save all the states via method onSaveInstanceState, and retrieve them when the calling activity was constructed again.
Further more, I also found out that, all the information stored in the memory is prone to be erased, like those Singleton objects. Thus I have to do saving by some persistent storage approaches, and restore them later.
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.
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.
I´ve an Android Application that holds some static objects on an class that extends Application class, using the same approach as exemplified here.
The objects that is hold by this class is shared and manipulated between all activities on my app.
Everything works well, but, some time ago, I noticed that when the application runs on backgroud for some time, when it´s restored, the data that was stored on the extended class has gone, and the app starts to throws a lot of NullReference exceptions.
I think that this happens because of the application was being temporary destroyed by the OS, to be recreated when we need to use it again.
So, how could I handle this scenario? Is there any way to discover that the application is being temporary destroyed, without subscribing to the onDestroy event of an Activity? On a test that I did, the onDestroy event was not called when I asked the background process of my app to being stopped.
Thanks a lot!
There is no way to determine when the proccess will be killed, so you always should store important data somewhere(sd-card for example) and restore it in onCreate() method of your App class.
Also take a look at onLowMemory() and onTrimMemory(), release all unnecesary data in memory to help the OS prevent destroying your app, cause one of the reason to determinate your app is a lack of memory.
No, there's no way to tell when you need to persist data that you store in static variables like that. There's no callback that the systems notifies you about this, at least to my knowledge.
So you should only use static variables to store temporary data, or cache data accessed from peristent sources. I've faced this problem in many of my projects, and I always ended up using intents / shared prefs / sqlite / etc. to reliable store data across Activities.
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.
I noticed that when my application encounters an error, the value of my application context variables are also reinitialized to its original value (not the updated value). Based from my understanding, this happened because the application was recreated.
How can I save and restore the values of my application context variables when an application error occurs? I'll also be glad if you could give a more detailed explanation on how things are working on the background of my application when it encounters an error.
Note: I read that one of the solution for this is by using SharedPreferences. However, SharedPreferences saves the data even when the application is dead. I don't want to save the data when the application is dead. I only want to save the data when the application is alive or on background.
How can I save and restore the values of my application context variables when an application error occurs?
First, don't have an unhandled exception.
Second, don't rely on static data members or custom Application subclass instances. There are many scenarios in which your process will be terminated and those values go away. They should be used for an in-memory cache of persistent content, and little else.
Sometimes, unhandled exceptions are truly unexpected, but these should be infrequent and usually tied to specific devices (e.g., ran out of storage space). Everything else represents a bug in your app, and you must fix the bugs.