onSaveInstanceState()/onRestoreInstanceState() in large application - android

I've got a complex application: an Application class and a bunch of Activity classes started as Intents from a common Activity.
According to the logs, the process is dying. It happens when I run my app, hit home, start up a whole bunch of other apps and then return to my app.
In the log, I see:
10-25 12:11:08.195: I/ActivityManager(2492): Process my.awesome.app (pid 20860) has died.
my.awesome.app then goes thru the onCreate() method of the main Activity as the app restarts.
However, I end up at the wrong screen because the instance variable that would direct me to the correct screen is not retaining the value it had when the app died. Actually, I'm hoping the app didn't die so much as it was killed by the system and then brought back to life.
Looking at the code, I see no onSaveInstanceState()/onRestoreInstanceState() methods so I'm pretty sure I need to provide them.
The question is which Activities need to provide onSaveInstanceState()/onRestoreInstanceState()/react to what they've done?
Let's say I'm a couple of Activities deep - that is, my Application class has started an Activity class that started a Thread to run an Activity and itself is running another Activity via an Intent.
Do all the involved classes need to provide/react to onSaveInstanceState()/onRestoreInstanceState()? Is it just the Application class since that's where I'm detecting the improper value that sends me to the wrong screen?

onSave/onRestoreInstanceState isn't really for application wide settings. It's more for settings particular to a single activity.
If you always want to go back to a certain activity after a process has been killed, you should probably save the last open state into a preference, and then in onCreate of your main launcher activity, launch the desired activity based on the value of the saved preference.

Related

Prevent activity from being destroyed as long as possible

I have an app, a single activity app with fragments in it.
The usual use case for this app is, that you start it and put the phone away and every now and then, you get back to the phone and insert some data... It's a logging app, you are doing something and insert your results into the app...
I have the problem, that every now and then, my activity get's destroyed and is recreated with an empty bundle... (Most of the time this is not the case, but every now and then this happens...). My app sometimes starts a service, even this service is killed in this case...
This means, that the system has killed my app, does it? How can I avoid this?
I need to keep the user data and the current top fragments... And they are saved to the bundle and everything works as long as their states and the data get saved...
Btw., my activity is always the TOP ACTIVITY, only that the screen turns off often... I just want to keep my activity alive as long as possible until the user leaves it with the back button... Or to save the state reliably
IMPORTANT NOTE
onSaveInstance does not always work (it's not part of the lifecycle and therefore not guaranteed to be called)... it only works most of the time... I need a way to that works always... If android kills my app...
don't keep your app in memory
You don't want to block Android from killing your app. What you want is to restore your app's state properly. Then the user will never notice the app has been destroyed and the user still gets the benefit of an app that was destroyed when not in use.
If you really want this use a wakelock. This will drain your users battery so I think twice before implementing this... Info at How do I prevent an Android device from going to sleep programmatically?
onSaveInstanceState explained
To do so check what information is needed in the bundle and persist that information with the onSaveInstanceState(bundle:Bundle) method so you can reuse it in onCreate(sameBundle:Bundle).
More information available from Google documentation at Save your Activity state and Restore your Activity State.
About Android Activity lifecycle
As stated by #prom85 in the comments below it's not guaranteed that the onSaveInstanceState method will be called because it's not part of the lifecycle. Workaround for this is using the onPause lifecycle hook to ensure your data is stored.
More information at Android: onSaveInstanceState not being called from activity
I had a similar problem, I arrived at this post while searching for a solution, you have to play with the manifest to achieve this and also understand what exactly activity is, in Android eco system,
In Android activity is a task which has a pre defined work.
I dig a lot in the documentation, I found that, we can configure activity in two ways,
Persistent
non persistent
if you mention for the activity in the manifest as
android:persistent="true"
and run the below use case
Start the APP
Press back or home button
you select the activity in the back stack again to bring it to front
Activity enters start -> pause -> stop - > resume , it does not get into onDestroy method.
if do not mention
android:persistent="true"
for the same use case
Activity enters start -> pause -> stop -> destroy, and if you select the activity from the back stack
Activity enters resume->create->start
If you want to run a service/task on activity start which keeps running when the app is in back stack, then you have to start that in the onCreate method, and kill them onDestroy by specifying your activity as persistent in manifest.
I hope my above solution might help others who arrive here for the same problem

About the life cycle of an android component

First of all, I'm new in android developing...
I had read some article in android API guide and feel confused about the component life cycle with the hosting process.
Here is my understanding:
Android system may kill some activities in a process or the whole process in low memory situations,which means there is a possibility that a started activity may die, but process still alive.
If a service is started and not call any stop method, when in extreme low memory, this service is killed by system with its hosting process, not just the service itself, means this circumstance should not occur:service is killed by system, but hosting process still alive.
When an app starts, the user navigates activity1 -> activity2 -> activity3 and none of them call finish(). Next, the user navigates to another app's activity and plays with it so long that the former app process is killed by the system. Now the user navigate back to activity3 in the back-tracking stack, what will happens? The former app process restarts with only activity3 recreate?
Anything wrong ?
There is no need to switch to another app's activity: from the moment that you leave the first activity to go to the second activity; there is a clear possibility that the first activity might have been destroyed when you return on it from the second activity (back-tracking) and when you go to a third one, either the first one, the second or both of them can be possibly destroyed in the mean time. In fact, you don't even to leave an activity to see it destroyed; as this will automatically happen simply if you switch from the portrait mode to the landscape mode and vice-versa by rotating the device.
When you return to an activity, the onRestart() function will be called if the activity has not been destroyed in the mean time. If it has, the "onCreate(Bundle savedInstanceState)" will be called instead but with the argument "savedInstanceState" set to a non-null value (ie, it will point toward a valid Bundle object) if you have took the precaution of saving the current state of the activity in the "onSaveInstanteState(Bundle outState)" function when the activity has entered the process of being destroyed by the system. The system will always call this function before destroying an activity when this one need to be restored later for back-tracking. Of course, it won't be called after a call to finish() because this will also remove the activity from the back-tracking stack.
Finally, in Android, the coupling between activities in the same application is very loose. When it comes to the use of resources, there is not much of a difference between switching to an activity from the same application or from another application. In many ways, activities will behave like if there were all fully independant applications when it comes to running. This is why you always need to use an intent to start an activity; even when it is from the same application.
Based on my understanding ...
In android during low memory situations, first activities would be removed from memory where the onDestroy method gets called.
This is not the case always. It depends on how the service is started i.e whether from onStart or through Binding the service with a component.
Once the former app process is killed, then when the user launches the application, he will be taken to activity 1. Launching the activity in same task or different task depends on launch modes used (single task, etc)

Android Application Class Lifecycle

The android app I am working on overrides the Application class to store lightweight state (username, gps location, etc) in static vars. Most of this state is set in OnCreate of the launch activity (username retrieved from prefs, location listener runs). Is it safe to rely on the launch activity to initialize the Application class? Are there any cases where the Application class might be re-created without the Launch activity also being created?
The question comes up because I ran into a null pointer exception accessing a variable in the Application class on resuming the app after the phone was asleep for several hours (the app was left in the foreground before phone went to sleep). Is it possible that the process was killed while the phone was asleep and on waking the phone, the Application class was re-created, the top activity in the stack was resumed, but the launch activity.onCreate wasn't run thus the Application class wasn't initialized?
Note that I have tried to test these kinds of scenarios by Forcing the App to stop using Settings / Manage applications. However, I'm not able to recreate the problem. On the next run, the Application class is created, followed by the launch activity.onCreate.
Is it safe to assume that the Application class instance will exist as long as the process, and that when the Application class is created it is equivalent to "restarting" the application ie. start with a new activity stack (and first activity on stack is the launch activity)?
No. Your entire application can be killed and recreated with the task stack intact; this lets the system reclaim memory on devices that need it while still presenting a seamless illusion of multitasking to the end user. From the docs:
A background activity (an activity
that is not visible to the user and
has been paused) is no longer
critical, so the system may safely
kill its process to reclaim memory for
other foreground or visible processes.
If its process needs to be killed,
when the user navigates back to the
activity (making it visible on the
screen again), its onCreate(Bundle)
method will be called with the
savedInstanceState it had previously
supplied in
onSaveInstanceState(Bundle) so that it
can restart itself in the same state
as the user last left it.
That is, the process (which the Application is tied to) can be killed off but then restarted, and the individual activities should have enough info to recreate themselves from what they've saved before being killed, without relying on global state set in the process by other Activities.
Consider storing persistent shared state that needs initialization by an Activity in either a SharedPreference or SQLite database, or passing it to Activities that need it as an Intent extra.
You can test the scenario by killing the process of your running application.
Step 1. Open your app, and then press Home button to hide it into background.
Step 2. Invoke adb shell
Step 3. Enter command su (you have to get ROOT permission in order to kill process)
Step 4. ps (list all running process ID and find yours)
Step 5. kill 1234 (assume your application running on process 1234)
Step 6. Then, go back to your device and click the launch icon again. You may find the last activity on activity stack is reopen. You may also find onRestoreInstanceState() method is called for the activity.
In short: do initilization in YourApplication.onCreate, not some LaunchActivity
Docs to check:
- Processes and Threads
- API Guides > Activities
Is it safe to rely on the launch activity to initialize the Application class?
Yes, as long as you remember that Application can exist longer that Activity and the Activity may be killed and recreated. I am not sure what Intent will resurrected Activity get: LAUNCH or VIEW
(For scenario when activity was killed as too heavy, while there was long running service binded to app )
Are there any cases where the Application class might be re-created without the Launch activity also being created?
yes, if the last visible activity was not LaunchActivity
check Android application lifecycle and using of static
Is it possible that the process was killed while the phone was asleep and on waking the phone, the Application class was re-created, the top activity in the stack was resumed, but the launch activity.onCreate wasn't run thus the Application class wasn't initialized?
If there were several different Activities launched A, B, C and them whole process killed, then I think Android OS is good with only creating Application and C activity, while A and B would be re-creted on access, that is on returning to them.
Is it safe to assume that the Application class instance will exist as long as the process,
yes
and that when the Application class is created it is equivalent to "restarting" the application ie. start with a new activity stack (and first activity on stack is the launch activity)?
I not sure when restarting the launch activity would be called first,
but the last, i.e. the one that user should see.
"I ran into a null pointer exception accessing a variable in the Application class on resuming the app"
Check this link..
http://www.developerphil.com/dont-store-data-in-the-application-object/

How does Android's Activity lifecycles work in relation to the entire Application?

This doesn't appear to be well documented or I missed it, so before I run a bunch of my own tests I was wondering if anyone already knows the answers to some of these questions.
First off, when I say "Application" I am referring to extending the Application class. http://developer.android.com/reference/android/app/Application.html
The questions I have are as follows, some are related.
When an a user leaves an Activity from within the Application, and goes to the Activity of another application, does the Application somehow get paused as well, even though it doesn't have an onPause()? Or does it continue to live unpaused until all of it's activities are destroyed?
when does the Application stop? When all of it's Activities are destroyed?
Is there ever a chance that one of the Applications Activities could be running without an instance of the Application, or will the Application class always exist if one of the Activities does?
If there is some process running on the Application, and it's Activities are all paused, will that process continue to run?
Is the Application effected by rotation in any way or does rotation only change Activities?
Thanks
As you say the application does not have onPause so nothing happens to the application. When onPause gets called in your Activity nothing special happens, your Activity continues to run and can do whatever it wants including run new threads, timers can go off, whatever.
I believe what you are asking is: when is an Application destroyed and when the onTerminate method in an Application called? The answer is hard to pinpoint and is up to the system, it does not necessarily happen when all activities get onDestroyed called. In fact even when onDestroy is called, your Activities aren't necessarily garbage collected. When the system gets low on memory the process that your Application lives in can be killed, meaning your Application will disappear; onTerminate may or may not be called. At that time all the Activities, Services, etc, are killed too.
The Application is always instantiated first, an Activity must have an associated Application, just like how you define it in the AndroidManifest.xml.
Processes never pause in Android, the onPause method does not actually really do anything other than tell you to pause things in your app. Other than that the process keeps chugging away, your threads keep running, even the main thread receive Intents with a BroadcastReceiver.
The Application gets rotation callbacks in the Application's onConfigurationChanged(). I'm not sure if you can disable that since there is no configChanges attributes supported by application tags in the AndroidManifest.xml.
A good comparison to Application is static field in any of your classes. The static fields will live as long the process is not destroyed, just like the Application. Static fields can be accessed by all Activities, Services, etc (assume the static fields are public), just like your Application.
Good Luck!
Jacob
The easiest way to understand this is to just forget that Application exists. Application has nothing to do with the application lifecycle. It is just a global on a process, that can be useful for some things, but is not needed for anything. Everything about how an application runs revolves around the Activity, BroadcastReceiver, Service, and ContentProvider components declared in its .apk.
An instance of Application can continue to exist after your last Activity is destroyed. Even if ALL activities are gone (ie. have all had their onDestroy methods called), the Application instance could still exist.
This application instance could be "re-used" for what you might otherwise think are two separate runs of your application.
This is all explained in detail here: http://developer.android.com/reference/android/app/Activity.html. If you read through it, you should understand everything.
Real quick:
Every activity has an onPause. You can choose not to override it, but it'll get called nonetheless. As soon as you switch away, onPause will be called.
Define "stop". Define "Application". The process may linger around forever, but it'll simply sleep and wait until one of its activities is started.
It's impossible for an activity to exist without being instantiated.
Every code executed runs in a process, so there's always one process for your app. The process will continue to exist after you switch to a different app, but it'll be in sleeping state. Android could at any time kill the process if system resources run low.
Every time you rotate the screen, your activity will be destroyed and recreated, unless you specifically disable that.

If my application goes to background, it still continue working? (sending/getting data from internet)

i am working on an application that send and get data from internet each 5 min
if i press home key and my app goes to background... it will still continue sending/getting data from internet? or i have to do something special?
thanks
"If an activity is completely obscured by another activity, it is stopped. It still retains all state and member information, however, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere. If an activity is paused or stopped, the system can drop the activity from memory by either asking it to finish, or simply killing its process. When it is displayed again to the user, it must be completely restarted and restored to its previous state."
http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
No. Activities shouldn't be depended on to process tasks in the background.
The following link illustrates the fundamentals of different Android components and what they do, i.e. the "parts" of an app.
You should be using a Service for background processing.
From what you're saying, I'd suggest an IntentService fired by an Alarm.
Application Fundamentals

Categories

Resources