Android prevent restoring the activity - android

I have a viewpager holding many fragments. When the activity is sent to background and when resources are needed, the OS will kill the app or at least some fragments. When I return to the activity it crashes because the activity tries to attach new instances of all fragments it held before the clean-up and now some fields are null. This of course could be fixed by properly implementing state saving and restoring using Bundles, but I don't want to do that.
Instead I want to prevent restoring the fragments. Is there a way to tell the OS that once it has sent the GC in and destroyed fragments, it shouldn't bother recreating them at all? Once the cleaning-up happens, I want the activity to be simply recreated on return, as if a user launched it by taping the icon. Any chance of doing that?
The proposed solution here https://stackoverflow.com/a/15683289/552735 does not work. It causes exceptions
java.lang.IllegalStateException: Fragement no longer exists for key f2: index 3

I had a problem just like this. Here's how I fixed it:
#Override
protected void onSaveInstanceState(Bundle savedInstanceState)
{
savedInstanceState.clear();
}
Note that this method will ensure that absolutely no UI state information will be stored when the Activity is killed by the system - this has the effect of also not restoring any Views when onRestoreInstanceState() gets called with the same Bundle after onStart().

You can't disable the save/restore instance state actions. In case you don't want to actually implement this logic, you have to reload the form especially if your form heavily loaded with fragments.
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
startActivity(new Intent(this,YOUR_ACTIVITY.class));
finish();
}

Related

Does android clear data in Views when app moves to background?

I have the following security requirement for my app :
Verify that the app removes sensitive data from views when backgrounded.
My question is, Does Android remove data from views when backgrounded ?
What i know as per android documentation is that :
By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText widget).
One solution is that i can clear all views then use below approach to save state
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
But i have no idea of whether Android os clears data in views.Any help will be appreciated.
Thanks
Android does not automatically recycler your view as soon as your application moves to background.
The system kills processes when it needs to free up RAM; the likelihood of the system killing a given process depends on the state of the process at the time.
It just recycle views if it decided to kill them or if it's in need for memory. Or upon a configuration change.
A user expects an activity’s UI state to remain the same throughout a configuration change, such as rotation or switching into multi-window mode. However, by default the system destroys the activity when such a configuration change occurs, wiping away any UI state stored in the activity instance.
Overall I think you had the right approach.
And just use onStop() (and not onPause() because of some Dialogs and other intercations that removes focus from your Activity) to clear your views if you want to.
Take a look at the android activity lifecycle https://developer.android.com/guide/components/activities/activity-lifecycle
One way to make sure all your data is cleared is to override the onPause function and clear your data manually. onPause is called when your application moves to the background.
No, it does not remove data because, according to the lifecycle of Android, when you do background the views, onPause() and onResume() is called and your views and its instances are in onCreate() method.
So, by launching the views from background, it does not remove your data of views.

Android Activity being randomly Created and Destroyed

I am not understanding how android activities are managed.
I have an activity and every once in a while i have noticed that, when my app goes into the background, android destroys whatever the current activity is (say Activity3) and several other singletons and objects etc. Thats fine. The problem is when the app is resumed then intuition tells me that since android has destroyed the activity and objects for memory or whatever, then android would just restart the app completely from Activity1 so all the objects and data members would get properly initalized.
NOT SO!
It seems that when my app is resumed, the Activity3 is recreated and onCreate is called with the same parameters as it was the first time (when it was called from Activity2) only this time all the singletons and other objects that were initialized in Activity1 and Activity2 are recreated with their default values and are rendered useless.
How is this a safe policy/technique? How can android just randomly destroy objects and activities and then when the user resumes just call onCreate on the recent activity and expect everything to be hunky doory and NOT have to go through the proper startup procedure/initialization?
UPDATE / SOLUTION
Thanks to the commentors for their excellent info.
ACCORDING TO ANDROID DOCUMENTATION
onCreate
Bundle: If the activity is being re-initialized after previously being shut down then this Bundle contains the data it most recently supplied in onSaveInstanceState(Bundle). Note: Otherwise it is null.
THEREFORE what I ended up doing is I set TWO flags. One in onSaveInstanceState in the Bundle so to know that it is a valid Bundle set by me. The other in the class itself to determine if onCreate was called because of recreation or Auto-Rotation. And so in onCreate I checked to see if onSaveInstanceState is not null, check the Bundle flag, and check bInit (which defaults to false). If both flags are true then it means android dumped and destroyed our apps memory and the safest way to ensure everything is initialized again in a linear-style application is to just restart it and launch the beginning activity.
public class SomeMiddleActivity extends AppCompatActivity
{
private static boolean bInit = false; // only way it will be false again is if android cleared our memory and we are recreating
#Override
public void onSaveInstanceState(Bundle state)
{
// set a flag so that onCreate knows this is valid
state.putBoolean("StateSaved", true);
super.onSaveInstanceState(state);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
// this must be called first always for some reason
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
{
if (savedInstanceState.getBoolean("StateSaved", false) && !bInit)
{
// we were recreated... start app over
Intent intent = new Intent(getApplicationContext(), Startup.class);
startActivity(intent);
finish();
return;
}
}
bInit = true; // this will stay true until android has cleared our memory
.......
}
Although this has worked thus far, if anyone has a different suggestion let me know. I will be posting another article on this.
And FYI: the onSaveInstanceState(Bundle, PersistableBundle) version of onSaveInstanceState is never called ever so I dont know why they even implement it. (?)
#goldenb #Rishabh Thanks to goldenb and Rishabh for the insight.
Android, if destroys, also gives you tools to handle it.
Mobile devices have limited amount of memory which needs to be shared among Applications running simultaneously. Thus, smart resource allocation is necessary. The Apps running on foreground are used by End-User and gain high priority for better performance and user experience. Thus, applications running in background need to release the resources to suffice the memory requirements for foreground applications. Hence, background applications are destroyed (not completely) sometimes (in case of low memory).
Android Activities have Callbacks likes onSaveInstanceState() and onRestoreInstanceState() which enable you to save your current state of Activity (i.e., values of variables) when it is destroyed and retrieve them when the Activity is recreated.
You can get more information from here: How to save and retrieve the state of Activity using onSaveInstanceState and onRestoreInstanceState.
You can perform validations on the retreived state to ensure the Activity performs exactly as it was doing pre-destruction. You would find it very easy and logical once you get hands-on it.
Just giving my 50 cents on the issue. The correct way to deal with the issue of an activity being killed by the system for its resources in background is a common problem in android and according to Google the solution for this is:
onPause() is where you deal with the user leaving your activity. Most
importantly, any changes made by the user should at this point be
committed (usually to the ContentProvider holding the data).
Emphasis is mine. But what this means is that the Android lifecycles are designed so that under normal conditions onPause should be called as an Activity or Fragment is sent to the background. They hint at this in several of the android documentation pages:
As your activity enters the paused state, the system calls the onPause() method on your Activity, which allows you to stop ongoing actions that should not continue while paused (such as a video) or persist any information that should be permanently saved in case the user continues to leave your app.
Also worthy of your attention: if you wish that views are restored during Activity recreation, you should have set the ID attribute of all views ;)
Note: In order for the Android system to restore the state of the
views in your activity, each view must have a unique ID, supplied by
the android:id attribute.
PS.
You were wondering why onSaveInstanceState(Bundle, PersistableBundle) is not called, one possibility is that you do not have the right activity attribute set
This is the same as onRestoreInstanceState(Bundle) but is called for
activities created with the attribute persistableMode set to
persistAcrossReboots..

How do tell if the Activity state has been destroyed and needs to be recreated

I have a list activity which does the usual list activity type stuff. All of the activity setup was being done in the onCreate() method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_streams);
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
mActionBar = getActionBar();
mStreamListAdapter = new StreamListRowAdapter(this, R.layout.stream_list_row);
mStreamListView = (ListView)findViewById(android.R.id.list);
mStreamListView.setAdapter(mStreamListAdapter);
}
I do not have onStart() and onResume() overrides. I can successfully navigate out of this activity based on the menu buttons pressed and then navigate back to this activity. When I navigate away from this list activity via startActivity(newIntent), I do not call finish, but I do call finish in the newIntent activity, when coming back to this list activity. Everything works fine, unless either the ListActivity itself or one of the new Activities have been sitting in the background for a long time (i.e. I switched to another app). Long time is measured in hours. Sometimes (NOT always), when I come back to my app after this delay, the list activity does not display the list, the menu is not displayed either, just a blank screen with the activity title displayed in the ActionBar.
I realize that I need to handle coming back to the list Activity via onResume() (and maybe onStart()). But onResume() is always called after I navigate back to this list activity, how do I really know if the variables representing the ListAdapter and ListView have actually been destroyed by the OS and need to be recreated inside onResume(), I don't want to recreate them every time onResume() is called. Can I just check to see if they are equal to null? It's hard to test this, as this does not happen very regularly.
Thank You,
Gary
It sounds like you are missing some basic information about Android and Activity's lifecycle. First I want to mention how Android saves it's state. There are 2 important points here. When leaving an Activity it is at risk of being destroyed it calls the hook method
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("myKey1", 1);
outState.putString("myStringKey", "hello");
}
When this is called, this is a chance for you to save all the data that you'd like to persist. This could be ids, strings, arraylists, and nearly any other type of data.
Now that you've saved your data, in the onCreate method of your Activity you are passed back all of these values.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
String myStr = savedInstanceState.getString("myStringKey");
int myInt = savedInstanceState.getInt("myKey1", -1);
}
// do the rest of your setup
}
On the first time onCreate is called savedInstanceState is null. To answer your question: "how do I really know if the variables representing the ListAdapter and ListView have actually been destroyed by the OS" this is how you can know. If savedInstanceState is not null, your stuff has probably been destroyed. However, I will say that anytime onCreate gets called that Activity was already completely destroyed anyway.
The other thing I will mention is Android is allowed to kill your backgrounded Activity whenever it needs to reclaim some memory. When it does this, it will call the onSaveInstanceState method for you. Android does not have to restart the application at the "first" or "MAIN" screen of your application. It can start off several Activities in if that's where the user left off. I mention this because it sounds like you're having issues whenever Android decides to create your activities after it clear's it's memory. The best way to make sure your application works well when this happens is to just rotate the phone. Rotate the phone from horizontal to landscape and/or back will cause the Activity to be destroyed and recreated with onSaveInstanceState called and passed back in to the onCreate. Based upon the information you've provided this is the best I can suggest for now.
Cheers.
I have finally figured out what was going on. I have 2 activities, ActivityA and ActivityB, and an Application object. Upon the application launch, ActivityA initializes some globals that are stored in the Application object and then starts ActivityB. When my app is restarted after being in the background for a long time, the onCreate() of the Application is called and then onCreate() of ActivityB is called. ActivityB relies on the variables in the Application object that normally are initialized by the ActivityA, but ActivityA is never called this time around and the globals are not initialized. I am still not clear why the ActivityA just hangs, instead of crashing with some message stating that the variables are null, which is what onCreate() in the Application object sets them to, but regardless, when this occurs, I need to go back to ActivityA() and reinitialize everything as I normally would, when the application is launched.
I now have a boolean in the Application object that indicates whether or not ActivityA has been executed after the onCreate() of the Application object has been called. ActivityB checks this boolean flag, and if not set, then simply start ActivityA to perform the on launch type initialization. I actually have to do this check in pretty much every activity.

Is onRestoreInstanceState() called only in case of screen rotation? [duplicate]

This question already has answers here:
onSaveInstanceState () and onRestoreInstanceState ()
(13 answers)
Closed 9 years ago.
I have a question regarding Activity Lifecycle in Android.
I want to know, in what situation the method onRestoreInstanceState() is called ?
The documentation says
"The system calls onRestoreInstanceState() only if there is a saved
state to restore"
But I want to know when can this situation occur. Is it only applicable in case of screen rotation, when the foreground activity is destroyed and recreated ?
From the link here:
onRestoreInstanceState() is called only when recreating activity after it was killed by the OS. Such situation happen when:
orientation of the device changes (your activity is destroyed and recreated)
there is another activity in front of yours and at some point the OS kills your activity in order to free memory (for example). Next time when you start your activity onRestoreInstanceState() will be called.
In contrast: if you are in your activity and you hit Back button on the device, your activity is finish()ed (i.e. think of it as exiting desktop application) and next time you start your app it is started "fresh", i.e. without saved state because you intentionally exited it when you hit Back.
Other source of confusion is that when an app loses focus to another app onSaveInstanceState() is called but when you navigate back to your app onRestoreInstanceState() may not be called. This is the case described in the original question, i.e. if your activity was NOT killed during the period when other activity was in front onRestoreInstanceState() will NOT be called because your activity is pretty much "alive".
All in all, as stated in the documentation for onRestoreInstanceState():
Most implementations will simply use onCreate(Bundle) to restore their
state, but it is sometimes convenient to do it here after all of the
initialization has been done or to allow subclasses to decide whether
to use your default implementation. The default implementation of this
method performs a restore of any view state that had previously been
frozen by onSaveInstanceState(Bundle).
As I read it: There is no reason to override onRestoreInstanceState() unless you are subclassing Activity and it is expected that someone will subclass your subclass.
Not only that, but also:
Usually you restore your state in onCreate(). It is possible to restore it in onRestoreInstanceState() as well, but not very common. (onRestoreInstanceState() is called after onStart(), whereas onCreate() is called before onStart().
Use the put methods to store values in onSaveInstanceState():
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
icicle.putLong("param", value);
}
And restore the values in onCreate():
public void onCreate(Bundle icicle) {
if (icicle != null){
value = icicle.getLong("param");
}
}
You do not have to store view states, as they are stored automatically.

Activity Life Cycle Methods and Saving State

I started reading around about the activity life cycle callbacks and saving state and there are quite a few things I don't understand - I'm writing an android app but I want to ask more general questions than how to do it specifically for the few activities etc I have at the moment, I would like to have a better overall view of how this works!
There are two groups of methods I have seen being used (I have seen one or two others but don't want to confuse myself even further...)
onPause, onResume etc,
and then the onSaveInstanceState ones.
What is the difference between them and the circumstances we should be looking to use them? I have seen some questions where a poster is using one of the normal life cycle callbacks, and is told to use onSaveInstanceState instead, so when should we be implementing onPause rather than onSaveInstanceState and so on. Some posts mentioned about methods being used for transient state only, could someone expand on that?
I have seen state being used to mean slightly different things - UI/View state and Activity state, what is the difference between the two?
I am also a bit unsure with what they mean by state, when we are saving state what kind of things are we saving exactly, could anyone give some quick examples (I don't mean actual code)? The android developer guides say that the android system automatically takes care of some of this, so what should we be concerned with? Bundle objects used by onCreate and onSaveInstanceState only store simple values, so what about more complex objects and arrays.
Thanks
protected void onPause ()
protected void onSaveInstanceState (Bundle outState)
Just by looking at it, onSaveInstanceState has an Bundle you can put your things you need to save in it. And get it back in onCreate(Bundle) or onRestoreInstanceState(Bundle);
Some important lines in the document:
This method is called before an activity may be killed so that when it
comes back some time in the future it can restore its state. Do not
confuse this method with activity lifecycle callbacks such as
onPause(), which is always called when an activity is being placed in
the background or on its way to destruction, or onStop() which is
called before destruction.
Android can destroy your activity or even kill your process at any given time (not likely when it is visible to the user though :-)). When the user navigates back to the activity, the data/info that was shown on the screen before he or she left it should be shown again.
The onSaveInstanceState callback allows you to do this.
Most of the Views already do this for you automatically. E.g. the current text in an EditText, the current scroll position of a ListView, etc. are all automatically saved for you.
However, there are some things that are not automatically saved for you. E.g. the current text in a TextView, the (changed) background drawable of a particular View.
Say, you show an error message after a user action fails. The error message is then shown in a TextField and this TextField's background becomes red (i'm just making this up here :-)). When the user leaves the activity while this error is shown (e.g. presses Home button), the activity is destroyed, the error message and the red background won't be shown again when the user comes back to the activity.
This is where onSaveInstanceState comes to the rescue.
You can save a String in there that containts the error message. Then when the activity is re-created, the Bundle savedInstanceState of the onCreate is not null and you can query it for the error message. If this message is not null/empty, call setText on the TextView for the error message and make that TextView's background red.
try to use this code to save state
#Override
protected void onSaveInstanceState(Bundle outState) {
State s = new State(yourTextView.getText().toString());
outState.putSerializable(State.STATE, s);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
State s = (State) savedInstanceState.getSerializable(State.STATE);
yourTextView.setText(s.getYourTextViewText());
}

Categories

Resources