android fragment crashes on resume - android

I know this is not a question but I've been struggling with this issue for a long time, whenever i work with fragments, when I leave the app (not destroyed, just click on home button) and I return to it after some amount of time, it gives nullpointerexception for all my variables and everything, I know this is a memory issue where it clears some space for other apps, but how can I workaround this and protect my objects from beeing destroyed,
thank you all

Have a look at
onSaveInstanceState(..)
This gets called when user minimizes your app -> by hitting the home button or when the OS is about to destroy your app. At this point you can save all the needed variables in the bundle that is passed in. This bundle is written to disk and passed back when your activity is recreated:
If you just want to retrieve your variables in the Activity you can use:
protected void onRestoreInstanceState (Bundle savedInstanceState)
Fragment do not have onRestoreInstanceState(...) but you can use onActivityCreated(...) to access the bundle if you want to retrieve your variables in the fragment.

Related

ContainerHolderSinglton.getContainerHolder().getContainer() becomes null when resume app after some time

when we resume app after some time ContainerHolderSinglton.getContainerHolder().getContainer() becomes null
I assume this happens when your app is in the background for some time, and you come back to the application.
This happens because your App's process gets killed as Android system need resources.
You should save all the variables you want restored in the onSaveInstanceState() method of your Activity / Fragments. You should save the variables inside the singletons and restore them in onCreate(Bundle savedInstanceState) method, from the savedInstanceState.
Android Activity Lifecycle

Using onSaveInstanceState With Multiple Activities

I have three activities in my application.
From the first one i started the second, and from the second i started the third. When the process of my app is killed by the system and i launch it again i see only the last active activity is being created. And it seems the only one that gets Bundle object as a parameter to its onCreate method.
There are two things I am curious of:
If the activity at the top of the stack is the only one that gets its bundle, why each of my activities got their callback (onSaveInstanceState) called just before their onStop() method.
If only one of my activities can retain original state, what about the others? Did they lose all their state just because system decided to kill my app process? Should i restore them manually? What about views on them? (normally views get their state back without needing me to put something into the bundle and later restore if i am not mistaken)
The default behavior is this (tested on 4.1.1):
When you start a new activity, onSaveInstanceState of the previous activity is being called
When the system kills the app, the state of activities back-stack is being saved
When you restart the app, the last seen activity is being shown and its onRestoreInstanceState is being called
When you navigate back and pop activities from the back stack, state of each of them will be restored with a call to onRestoreInstanceState passing the bundle that was obtained from the first step above.
Therefore, the answers to your questions are:
All activities will be restored, but not at once - the last one seen is restored immediately, while the others will be restored when you navigate back.
All simple views (e.g. EditText) will automatically restore their state. In order for this to happen, you need to make sure that a) you did not override onSaveInstanceState or onRestoreInstanceState without call to super implementations b) the views that should be restored have unique IDs in view hierarchy
onStop is called on previous activity when you create a new activity, so you are saving the state! Your previous activity's onCreate will be called, if it's destroyed, so don't worry about recreating views. Are you sure app is killed? An app is not killed when it loses view. Android will keep it in memory as long as it doesn't need to free memory.

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.

Application lifecycle and Bundle savedInstanceState

Can somebody clarify please why I have such a weird behavior. Up to documentation the Bundle savedInstanceState which is set in onSaveInstanceState() is alive as long as application alive, so when it it in foreground or background. After the application is being killed the savedInstanceState instance is killed as well. Here is what I have:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (savedInstanceState != null) {
Log.i("Dev", "not null");
} else {
Log.i("Dev", "null");
}
}
Here is how I set it:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("bool", true);
}
Then, I'm starting the application in the emulator. After application is opened I click home button so the Launcher is visible. Then I kill the application's process using adb. After that I start the application from the list of recently used application expecting for "null" in the Logcat, but what I actually see is "not null", so my understanding is incorrect?
The Bundle is saved for as long as Android wants it to be saved/can save it. One of the "features" (quotes because it ends up being a bad idea as often as it is a good one) of Android is that applications are never exited (to the user's view). Their mechanism of doing this is the onSaveInstanceState- it stores the Bundle, and when the app is later reinitialized by some method (such as from the recent activities menu) it will pass that Bundle to the onCreate and let it re-initialize itself.
Of course this also causes problems. For example, if you save login info, exiting an application won't log you out. So a user can then just hand his phone to a friend to watch a video, thinking that he exited his mobile banking app and is safe, yet the friend can call it back up and recreate it. If your app has large data structures in static variables or singletons they will not be recreated unless you code it carefully. Apps that require activities to be explored in order can be restarted from the middle.
Now Android can choose to forget your Bundle. If you put several MB in it, I would expect android to forget it rapidly. But it will remember it for as long as it can.
Isn't it very clearly stated here ? Or do I missunderstand your question?
[..]To save additional data about the activity state, you must override the onSaveInstanceState() callback method. The system calls this method when the user is leaving your activity and passes it the Bundle object that will be saved in the event that your activity is destroyed unexpectedly. If the system must recreate the activity instance later, it passes the same Bundle object to both the onRestoreInstanceState() and onCreate() methods.
I mean for me this is also reasonable in most situations. Because when your activity / app is in the background and the android system closes it (let's say because it needs more memory), then it first saves the state. So next time the users opens your activity, you can restore it's previous state (and that may also exactly be what the user wants, since it wasn't him who closed the activity, but the system itself).

Android Activity Lifecycle: restoring app after kill - design problem

atm I try to get my app working around "onSaveInstanceState" and "onRestoreInstanceState", but the deeper I dig, the the more problems occur.
So, for example, I just realized, that restoring one activity via those two functions is pretty useless. Because, if I press the back button and return to the activity before, this one doesn't get its "savedInstanceState" bundle and instead gets recreated completely.
Is there a way to restore the whole application instead of just a single activity? Or is this just a weird design and I shouldn't even bother with restoring one activity?
Kind regards,
jellyfish
Edit: ok, stupid me...
the bundle my main activity got was not null, but only in "onRestore...". In "onCreate" it was null indeed, but this was true all the time. (No matter if I came back from another activity after kill or not, for example)
So now I'm confused in another way: I have tested this before in another activity, and there, the savedInstanceState bundle of "onCreate" and "OnRestoreInstanceState" where the same! Is this just random or something special of the main activity? (Tried different launch modes as well, but they had no impact).
So, for example, I just realized, that restoring one activity via those two functions is pretty useless.
No, it is very useful, when used properly.
Because, if I press the back button and return to the activity before, this one doesn't get its "savedInstanceState" bundle and instead gets recreated completely.
No, it doesn't.
If it already exists and is on the back stack, it will be started (onStart()) and resumed (onResume()), but it is not created. If Android had to close the previous activity (e.g., due to a shortage of memory), the previous activity will be created (onCreate()) and will be passed a Bundle containing the data it populated in onSaveInstanceState().
The only way those statements would not be true is if you are monkeying with the BACK button processing.
Is there a way to restore the whole application instead of just a single activity?
No.
Or is this just a weird design and I shouldn't even bother with restoring one activity?
You most certainly should restore one activity.
onSaveInstanceState() is used for two scenarios:
If the user changes configuration (e.g., rotates the screen), your activity will destroyed and recreated. You use onSaveInstanceState() to pass data from the old activity instance to the new one.
The BACK button scenario I outlined above.
I have tested this before in another activity, and there, the savedInstanceState bundle of "onCreate" and "OnRestoreInstanceState" where the same!
Of course. They are supposed to be the same. If the activity is being created totally from scratch, onCreate() will be passed null and onRestoreInstanceState() will not be called. But if there is instance state, that state (Bundle) will be passed to both onCreate() and onRestoreInstanceState().
Is this just random or something special of the main activity?
Neither. They are supposed to be the same.

Categories

Resources