Additional Lifecycle Concepts and Realities


Being "Killable"

The Android developer documentation makes reference to an application being in a "killable" state. While Android tries to keep the process of an application resident even after it has exited (i.e. after onDestroy), it does need to be able to kill these processes in low-resource situations to reclaim memory. The states in which an application is killable differ per OS version. On all versions of Android, applications that have returned from onStop or onDestroy are silently killable. On versions of Android prior to Honeycomb, applications that had returned from onPause were also killable. Being killable simply means that Android reserves the right to terminate your application’s process at any time without running even another instruction of your app’s code.

In other words, if you have any state that must be recoverable (such as a player’s game progress, items, awards, etc.), you must save those to persistent storage no later than the last callback before entering a killable state.

In addition, while applications can run native threads even when they are in a killable state and even post-onDestroy, this is to be avoided, since the process kill will also kill those threads. This could cause all manner of corruption and shutdown issues.

Callback-Handling AND ANR’s

It may seem possible to avoid becoming killable by choosing not to return from the last callback before entering the killable state (e.g., onPause or onStop). This will not work. In fact, it will have disastrous consequences for your application that highlight another aspect of application lifecycle. Applications are required by Android to handle any posted input events within 5 seconds. Since that input is delivered on the same thread (the main or UI thread) as the lifecycle callbacks, blocking for 5 seconds in a lifecycle callback will break this rule.

When an application breaks the "5 second rule," the device user will be given an Application Not Responding (ANR) error dialog box. This will give the user the option of waiting for your (assumedly crashed) application to continue, or else kill your application. This is to be avoided in any application. Applications should carefully plan their callback code to avoid making blocking calls that could take an unknown amount of time. This includes such operations as large storage reads/writes and especially network operations, which should be done in spawned threads.

onPause versus onStop

In addition to the lifecycle state items previously mentioned, there is one other important difference between onPause and onStop callbacks. The onPause callback halts the visible UI thread, and thus any time spent in onPause will actively block the app’s UI interaction. Thus, it is important to make onPause as responsive as possible while still saving absolutely key application state.

The onStop callback, on the other hand, is called once the app is no longer visible. Thus, while it is important to avoid ANRs from this callback, it is not pivotal to return immediately from onStop. Spending a little more time in onStop will not cause application/device responsiveness issues.

Rendering and Threading

Related to callbacks and the potential for ANRs, it is important for applications to do their rendering in a secondary thread, either in Java or in native. If a native thread is to be calling OpenGL and EGL, it should be sure that it calls up to Java from native to bind the EGL context. The thread that is calling OpenGL ES must be the same thread that bound the context. The main UI thread should not bind the context and then have some other thread in native calling OpenGL ES. This is likely to cause problems. NVIDIA’s Tegra Android Samples Packs include examples of exposing EGL call wrappers in Java that can be called from native threads to make this easier.

 

 

 


NVIDIA® GameWorks™ Documentation Rev. 1.0.200601 ©2014-2020. NVIDIA Corporation. All Rights Reserved.