65

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)?

Patrick Cullen
  • 8,654
  • 3
  • 21
  • 23

4 Answers4

24

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.

Yoni Samlan
  • 37,905
  • 5
  • 60
  • 62
  • Also http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle) – KingCrunch Jan 03 '11 at 15:31
  • 1
    Ugh. Any suggestions on how to test this scenario? As I mentioned, when I manually kill the proc, the activity stack doesn't remain intact. – Patrick Cullen Jan 03 '11 at 17:01
  • As an aside, I recognize that Android team fully intended this behavior and prefers that we design our apps to hide the details of the app starting/stopping, but it would still be nice to have some concept of a user session. As it stands, its difficult to differentiate between "app was paused briefly" and "app was was paused for an extended period". Getting a gps fix can take a long time, and it would be nice if there was an easier way to mark the logical begin/end of user interaction so that you could decide whether to get a new fix or prompt for credentials. – Patrick Cullen Jan 03 '11 at 17:07
  • You could create Activity subclass(es) that save a preference for pauseTime() in their onPause() and remove it onResume(), with onCreate()s that look for that timestamp's presence and call some onNewSession() method in your Application if that timestamp's over a certain value, if you really wanted to... But the system's assumption is that the user is always continuing a session where they left off, unless they're gone for an especially long time (in which case the system will clear your task stack -- see http://developer.android.com/guide/topics/fundamentals.html#clearstack). – Yoni Samlan Jan 03 '11 at 17:42
  • You can test this by *leaving* your app (such as by going to home), and then killing the process. If you kill the process while the app is in the foreground the system will think something is broken in the app and do some cleanup like removing its top activity to avoid bad infinite restarting states that apps can get in. – hackbod Jan 03 '11 at 18:56
  • 1
    This doesn't seem to work for me. I tried on 2 devices (1.6 and 2.3) - I put the app in background with hard home key, then "Manual Stop" from Manage Applications, click my app icon on the home screen. The app still restarts with the launch activity. And its not just clearing the top activity - the stack is several activities deep when I put it in the background. And of course, android:cleartaskonlaunch isn't set ... – Patrick Cullen Jan 03 '11 at 19:28
  • I think the need for persistent application state is another reason to use ContentProviders. – louielouie Mar 14 '12 at 06:48
  • 6
    I'm most grateful for this Q&A because I've found that my application's global state, which is held in the `.Application` class, is quite frequently killed even though the `Activity` stack apparenty remains intact. To solve this, all of my Activities must be able to gracefully cope with the global state no longer being present the next time they come to foreground, and in such case trigger the rebuilding of the global state. – Trevor Jul 30 '12 at 15:14
  • 1
    An interesting additional observation I have is that while my app is in the background, its `.Application` (and presumably process) seems to be cyclically killed and then re-instantiated, depending on what else the phone is doing. So if the phone is playing music for example, if I have a `Toast` to indicate `.Application` instantiation, I'll often see the `Toast`. This happens on my HTC One X, which I believe to be a very good edge-case test device for this kind of behaviour, because the One X is known for running short on memory and even sometimes killing the launcher to free up RAM! – Trevor Jul 30 '12 at 15:16
  • 5
    Furthermore, I can only assume that the cyclic killing and re-instantiating of my app's `.Application` is the system attempting to improve user experience by getting ready again any processes it had to kill previously due to low RAM. What this has made me realise is that it's a bad idea to start off any lengthy work of rebuilding global state at the point of `.Application` instantiation. – Trevor Jul 30 '12 at 15:24
7

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.

Darren Shen
  • 81
  • 1
  • 2
5

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.

Community
  • 1
  • 1
Paul Verest
  • 60,022
  • 51
  • 208
  • 332
2

"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/

Tamal Samui
  • 738
  • 10
  • 14