DLG Software


Application development

  with JavaScript, Flex, and AIR


Overview

This provides tips on handling the Back key in AIR on Android apps:

  • closing your popups on an Android Back key press
  • keeping your app from exiting when Back key is pressed in your home view
  • special handling for Android apps based on Application class (rather than ViewNavigatorApplication or TabbedViewNavigatorApplication)

Review of view navigation

If you're familiar with developing AIR mobile apps you can skip this bit.

When you create an AIR mobile app you generally implement your view navigation using AIR's ViewNavigator class. AIR apps based on ViewNavigatorApplication or TabbedViewNavigatorApplication employ the ViewNavigator class to implement this common mobile navigation pattern:

  • app has a home view (or firstView) which calls other views,
  • these views often call other views to complete a task in a wizard-like sequence,
  • pressing the Back key returns you to the previous view,
  • often you have the option of "jumping" directly to the home view

ViewNavigator provides this navigation functionality through stack-based methods. You call its pushview method to push a view onto the stack (this displays the view) or use popView to remove a view from the stack (returns to the previous view). In addition to pushView and popView there are other stack-related methods such as popAll, popToFirstView, etc.


ViewNavigator's built-in navigation handles the Android Back key for you, no code required. As you’d expect in an Android app, pressing the Back key moves you back through previously displayed views (those currently on ViewNavigator's view stack) until there's just one view left. At that point (when there's no view remaining on the stack to pop to) a Back key press exits your app.


So, Android users expect certain behavior from a Back key press, and ViewNavigator provides this for your views. But Android users also expect a Back key press to dismiss popups. However, ViewNavigatorApplication has no built-in functionality for that; if you want your popup to close on a Back key press you'll need to provide that Back key handling yourself.


 
For more information on View navigation see my primer on Mobile App Development with Flex 4.5 or see Adobe's doc Developing Mobile Applications with Flex and Flash Builder.

Back key for popups

When you display a popup (using SkinnablePopupContainer.open() or PopupManager) that popup is NOT pushed onto the ViewNavigator's view stack. As a result, the default behavior of a Back key press is not what you'd want on Android – instead of your popup closing it is the view that responds. That is, the view navigator receives the key press event and responds by popping the view stack. As a result you see a view transition as a popView() executes, but your popup remains right where it was. Very ugly. Worse, if there's no view to pop to (i.e., you are at firstView) then that Back key press will close your app.


Luckily, getting your popup to honor the Back key is simple (see fig 1). All that's needed is to insert your own keypress listener into your popup. In your event handler you can close the popup and (very important) stop event propagation. That last bit is critical because without it the event will bubble and the default Flex behavior will still execute. Here's the code:


Set listener:

systemManager.stage.addEventListener(KeyboardEvent.KEY_UP, stageKeyUpHandler, false, 1000, true);


Event Handler:

protected function stageKeyUpHandler(event:KeyboardEvent):void
{
    var key:uint = event.keyCode;
    if (key == Keyboard.BACK)
    {
        event.stopImmediatePropagation();
        event.stopPropagation();                        
        closePopUp(); //calls routine to remove listeners, exec this.close(), etc
    }
}

FIGURE 1: Popup Back key handling


 
For Views you can make use of the backKeyPressed event to handle the Back key, but for popups you'll want to listen for keyboard events.

Special Case: Popups in your home view

As noted above, when there's only one view on the stack (i.e., no view left to pop to) a Back key press exits your app. You might expect the Back key handling described above to handle this situation, but it does not – create a popup with the key handling described above, display it in your home view (or firstView), then press the back key and… your app will still exit. Why? Because listening for a key UP event isn't enough in this case, since the processing that exits your app is triggered by a key DOWN event. Take a look at this ViewNavigatorApplicaticationBase.as comment:


// If preventDefault() wasn't called on initial keyDown event
// and application thinks it can cancel native back behavior,
// call backKeyHandler() method.  Otherwise, runtime will
// handle the back key function

Note the comment about "the initial keyDown event". Since key down events fire before key up events you need to exec your preventDefault() on a Back key down event to prevent exiting of your app – by the time the up event fires it's too late.


While you can prevent Back presses from exiting your app it's very important to do this conditionally -- you do NOT want to do this ALL of the time, only when a popup is on the stage. Remember, Android users expect certain behavior, and one convention is that a Back key press from a home view exits your app. So you need to inhibit exiting of your app only when a popup is being displayed. One simple solution is to query systemManager for the existence of active popups.

Below is the approach I took to handle this (I also tried handling the keydown events in the popup itself but got some very strange behavior, so settled on this approach). The code below goes in your application root class. Now you'll only prevent a Back key press exiting your app when a modal popup is on the stage.


Set listener:

systemManager.stage.addEventListener(KeyboardEvent.KEY_DOWN, stageKeyDownHandler, false, 500, true);


Event Handler:

// Prevent app close when there is no view to pop to and Back key pressed in popup
protected function stageKeyDownHandler(event:KeyboardEvent):void
{
    var key:uint = event.keyCode;
    if (key == Keyboard.BACK && !systemManager.numModalWindows==0)
        event.preventDefault();
}

FIGURE 2: Root class code to prevent app exit


  When testing your Back key handling keep in mind that what works in the Flash Builder emulator may not work on the device (e.g., pressing the Back key in your home view will exit your app on the device, but does nothing in the emulator).

Android Back key in <s:Application>

There's one more issue with the Android Back key, though this applies only to AIR mobile apps that use Application as their root class (rather than ViewNavigatorApplication or TabbedViewNavigatorApplication). Mostly this case applies to tablet apps, since that's where you have bigger screens and more memory and therefore are more likely to base your app on Application so you can implement custom view management and navigation (for an example of a tablet app based on Application see my Multiscreen app explorations - will make this available sometime in January).


By basing your mobile app on Application you get more control but you also lose some nice built-in functionality. This includes Back key handling.


In an AIR mobile app based on the Application class handling the Back key is your responsibility. And you do need to handle that Back key press else your app will have only one response to that key press – your app will exit. Imagine how annoying that would be to a user – they just want to close a popup, or just navigate to a previous view, but instead the Back key always closes the app.


The solution to this is similar to the one covered above in Special Case: Popups in your home view. That is, you define a keyhandler for a DOWN key, and then your event handler fires preventDefault(). However, for apps based on Application you need to listen for NativeApplication events. Do this in your Application root view and any of its states where you don't want a Back press to exit your app.


Below (figure 3) is an example of an app based on the Application class that uses states to display its primary views. In this example pressing Back when the Help or Preferences states are active simply returns you to the DataView state (which is the primary app state, or home view). Pressing Back in the DataView state will exit your app.


Here is the code for the app's main states:

<s:states>
    <s:State name="dataExploreState"/>
    <s:State name="globalHelpState"/>
    <s:State name="globalOptionsState"/>
</s:states>

Set your listener on NativeApplication:

NativeApplication.nativeApplication.addEventListener(KeyboardEvent.KEY_DOWN, nativeKeyDown);


Your event handler responds based on currentState:

// Back key closes app only if pressed in primary view (Data exploration view)
protected function nativeKeyDown(event:KeyboardEvent):void
{
    var key:uint = event.keyCode;
    if (key == Keyboard.BACK && 
        (currentState== StateEnum.GLOBAL_PREFS 
            || currentState== StateEnum.GLOBAL_HELP)) 
    {
        event.preventDefault();
        presenter.setState(StateEnum.DATA_VIEW) ;
    }
}

FIGURE 3: Code for Application root class to prevent app exit



References

Here are some links you might find useful.

Flex/AIR certification logo
About

JavaScript

JavaScript appdev primers

General JavaScript

SPA Demo Application

Backbone Demo Application

Recommended sites

Flex/AIR

Flex/AIR primers

Flex demo apps

all require Flash Player!

AIR mobile dev

SAS

SAS Introduction

Varia

About

Archives