Surprising Application Lifecycle Events and How to Handle Them


There are several confusing application lifecycle cases we have seen on numerous commercial devices and OS versions that we recommend developers test with their applications. This document will list confusing cases that we have frequently seen cause problems for real, commercial applications during the QA process. It will also discuss what an application can do to better handle the situation. For each of these cases, we recommend that developers use the simple Lifecycle application in the NVIDIA Tegra Android Samples Pack, editing the app as needed to replicate the exact case. This is not meant to be exhaustive – it merely lists some items that very commonly slip through most developers in-house testing.

Basic Concepts Behind the Problematic Cases

Configuration Changes

Configuration changes in Android refer to a set of system-level events that can strong affect application and UI behavior. These include such changes as:

Many of the issues discussed in the document revolve around device orientation changes, (either intentional, unintentional, or implicit based on device behavior in other lifecycle events). By default, if an application specifies no AndroidManifest.xml keys for configuration change handling, any configuration change will actually result in the application being completely shut down (onDestroy) and then re-launched in the new configuration. Needless to say, for a large 3D game, this can be extremely expensive. However, there are other options, whether the application wishes to support both orientations (landscape and portrait) or only one.

"Forcing" Landscape or Portrait Orientation

It is possible to request that your application always run in landscape or portrait mode with the AndroidManifest.xml keys:

android:screenOrientation="landscape" 

or

android:screenOrientation="portrait" 

On some OS versions and devices, this will keep the application from ever seeing any portrait configurations or seeing any issues. However, on other devices (we have seen this on Motorola Atrix and other devices), this tag behaves somewhat differently. Specifically, while it ensures that your application will "settle" to the requested orientation, on these devices and OS versions, we find that there may be considerable "thrash" between multiple orientations owing to spurious configuration changes.

On these devices, in several specific lifecycle cases discussed later in this document, the application may receive multiple configuration changes between the desired orientation and the opposite orientation. These spurious configuration changes can cause issues for applications in several manners:

  1. With the default behavior, each configuration change (sometimes as many as three in a row) will shut down and restart the app.
  2. Some of these "false starts" in one configuration or another may or may not complete all the way to a valid surface before shutting down, confusing some apps that expect each new launch to come all the way up to a fully working rendering surface and focus.
  3. Some of these "false starts" may launch all the way up to a full rendering surface with dimensions opposite the desired orientation before quickly shutting down again. Needless to say, these incorrectly-sized "false starts" can be very confusing to an application.

Handling Configuration Changes in a Lightweight Manner

Orientation
Note: Applications targeting API level 13 or newer must also use the screenSize configuration change tag. See the API Levels and Configuration Changes section for details.

The AndroidManifest.xml key:

android:configChanges="keyboardHidden|orientation" 

specifies that the application wishes to manually support orientation change events and software keyboard hiding change events. If this key is set for an application’s Activity, then rather than "bounce" (shut down and restart) the application's Activity on each orientation change, the application will receive two forms of notification in quick succession:

  1. The Activity's onConfigurationChanged callback (if overridden) will be called with the new configuration.
  2. The Activity's Views (specifically their SurfaceView Holders) will receive surfaceChanged callbacks.

In practice, we find that many applications do not even need to supply overrides for onConfigurationChanged (although having one installed can be useful for debugging), as they can simply change their glViewport and any aspect-ratio-handling in the surfaceChanged callback.

This simple flag and surfaceChanged handling code can often allow applications that have the ability to render their UI, etc in portrait and landscape modes to easily support fast orientation change. This flag avoids having the app shut down and thus can avoid having the app lose or destroy its EGL Context. Since the EGL Context stays resident, there is no need to do expensive reloading of 3D resources.

With this flag, note that the application may still receive surfaceChanged callbacks for the previously mentioned "false starts" with incorrect surface sizes. However, since the application receives only these change messages and not full shutdown/restart, these unexpected (temporary) surfaces of the wrong size can often be quickly ignored.

However, applications setting this flag do need to be prepared for surfaceChanged callbacks that happen more frequently than just once per surfaceCreated/surfaceDestroyed pairing.

Hotplug of Keyboard or Tablet Dock

As tablet-docking keyboards become very common, users will expect to be able to attach/detach these accessories without their games exiting and re-loading. By default, plugging or unplugging a keyboard or dock in Android is a configuration change, and if not handled via a manifest key will cause the application to be quit and restarted. The method of handling this in a lightweight manner is to add the “keyboard” key:

android:configChanges="keyboardHidden|keyboard|orientation"

This addition should cause the docking event to be sent to the application as a configuration change, not a restart.

API Levels and Configuration Changes

Changing your app’s API-level target (not the minimum, just the target) can change the behavior of the app. The most important of these is the screen size configuration change.

Changes to screen size can happen for various reasons; the most obvious is the connection of an external screen, such as an HDMI display. However, as of API level 13, a change that was previously passed along as another change is also passed along as a screen size change: orientation. This can cause applications that decide to upgrade their target to suddenly misbehave on device rotation.

The issue is that applications targeting API level 12 and below generally have the following in their manifest: 

android:configChanges="orientation"

On those API levels, this will cause device orientation to come in as a config change and not restart the app from scratch. All is well.

However, when the same app changes their manifest to target API level 13, they suddenly find that orientation change causes the app to restart, tearing down all of their content in the process. Fortunately, the fix is quite simple. API level 13 added the screenSize configuration change, which is used to signal any change in screen dimensions. Since orientation on a non-square display changes the height and width, orientation change also triggers this screen size configuration change. If the app hasn’t added the explicit manifest handler for it, then it will be shut down and restarted.

Thus, most (likely all) 3D games that target API level 13 or newer should add the screen size configuration change tag to their manifest:

android:configChanges="keyboardHidden|keyboard|orientation|screenSize"

 

 

 


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