h1.ViewNavigatorApplication - Functional and Design Specification
It is recommended that you read the ViewNavigator Specification before reading this spec.
ViewNavigatorApplication is a new application class designed to provide the basic infrastructure for building a native mobile application. The base class is meant to support the basic user experience paradigms commonly used by mobile applications today. A standard mobile application will consist of a series of full-screen views. A view can be thought of as a window of a mobile application that contains a set of components that represents the current user experience of the application. An application, including its logic, can be broken down into various views that are shown and hidden as needed. This application model is considered view-based, and ViewNavigatorApplication will take advantage of a full-screen ViewNavigator to manage this. In addition, ViewNavigatorApplication will tightly integrate with device events to enable support for automatic hardware key handling.
Usage patterns for mobile applications differ greatly from the desktop experience. An app is used for shorter time periods and is often interrupted by other actions, such as text messages, phone calls or other applications. More often than not, when an application is relaunched, the user expects its previous state to be restored. So the actual mobile session is short, but the session state should persist through each use of the application.
This image shows common usage patterns of a application on mobile devices
To help deal with this, ViewNavigatorApplication will be introducing persistence apis that allow view data to be saved in memory and eventually serialized to disk for later retrieval. This will provide a mechanism for developers to quickly and easily manage state between sessions.
ViewNavigatorApplication is not meant to be used for desktop or web applications as it requires the AIR 2.5 SDK and the Flex Mobile swcs (mobileComponents and mobileTheme).
Jack is creating a mobile application for his enterprise company. He wants his application to follow standard mobile ui practices, so he uses ViewNavigatorApplication to build an application. After creating the views of his application, Jack runs his application on an Android device. Since Jack used ViewNavigatorApplication to build his app, as he traverses his application, pressing the back hardware key automatically takes him back to the previous view. Also, when he turns his device horizontally, his views automatically show their landscape states. In addition, since Jack enabled session persistence in ViewNavigatorApplication, when he quits and relaunches the app, the application state is automatically restored.
Jane is creating a application that uses the ActionBar to display contextual action items for each application view. She would like the logo of her application to be visible in the titleContent area of the ActionBar on every view. Instead of duplicating code and setting this item as the titleContent for each view, Jane decides to use DesignView to set a global default for the titleContent area. To do this, Jane opens DV while editting her Application mxml file. DV displays the ActionBar with nothing in it. Jane then drags an image component to the titleContent area, which tells DV to set the Application's titleContent property to that image. Now when the application is run, Jane's image is shown on every view.
ViewNavigatorApplication should provide an easy way for a developer to quickly build a production level mobile user interface. This component will extend SkinnableContainer and contain a very specific ui structure defined through the use of optional skin parts. The developer can provide a skin that contains the top level ui elements that should be visible throughout the application's lifespan. The standard ui components are:
Since ViewNavigatorApplication uses a view-based Navigation scheme powered by ViewNavigator, no children can be directly added to a ViewNavigatorApplication tag. Instead, a developer will need to use the firstView
property or manually call pushView() on the navigator to define what View object should be instantiated when the application initializes.
Many mobile devices have the concept of an application menu. The purpose of this menu is to display global and contextual actions related to the current application state. When the menu key is pressed, ViewNavigatorApplication will automatically show the menu object with a set of generated items. When a menu is visible, clicking outside the menu or pressing the back button should dismiss the menu. This component is not used for contextual menus. The creation of contextual menu will be the developer's responsibility. See the ViewMenu Specification for more details about this component and how it integrates with ViewNavigatorApplication.
ViewNavigatorApplication automatically integrates with the hardware device keys of the device its running on. By default, ViewNavigatorApplication will automatically respond to the menu and back keys. When the menu button is pressed, the application's menu will be displayed (see Menu Spec). When the back key is pressed, ViewNavigatorApplication will check how many views are currently on the navigation stack of the main navigator. If more than one view is being managed, mobile application will automatically call popView() on the navigator so that it transitions to the previous view. If one or no views are currently stored in the stack, ViewNavigatorApplication will suspend the application and return to the device's home screen (Returning to the home screen is Android specific).
When the back key is pressed, the active view of the application will receive a cancelable "backKeyPressed" event. Canceling this event will prevent ViewNavigatorApplication from returning to the previous view. Customizing the back key logic can be done by listening to the "backKeyPressed" event or by overriding the backKeyHandler()
method on ViewNavigatorApplication or ViewNavigator.
A developer can always listen to the lower level KeyboardEvent to catch the menu and back keys. If they do it is important to note that Flex performs its hardware key handlers on "keyUp". So a developer will need to to cancel the ViewNavigatorApplication behavior or call stopPropagation()
on the KeyboardEvent.
Below are template properties that will be defined on ViewNavigatorApplication. These properties serve only as a proxy for the same values on the application's main ViewNavigator, and serve as the default values when the same properties aren't define on the current view.
Property
Description
actionBar
A reference to the ViewNavigatorApplication's actionBar.
firstView
Defines the first view to show when no sections have been defined.
firstViewData
The data object to pass to the first view of the application.
Properties related to ActionBar
Property
Description
title
The default title used in the action bar.
titleContent
The default UI components that should be displayed inside the ActionBar's content area.
titleLayout
The default layout of the content group that is holding the view's titleContent
navigationContent
The default UI components that should be displayed inside the ActionBar's navigation content area.
navigationLayout
The default layout of the action bar's navigation content group
actionContent
The default UI components that should be displayed inside the ActionBar's action content area
actionLayout
The default layout of the content group presenting the action content
Storing properties locally to a device is a common task that many mobile applications use to save user and state information. The Flex Mobile framework introduces a new manager that can be used to store data to disk using a simple API. This object is called the PersistenceManager
and it implements the new IPersistenceManager
interface. The persistence manager has a short list of apis that a developer can use to save and manipulate data managed by it. They are:
Method
Description
setProperty(key:String, value:Object)
Stores a value object in the data store using the passed key
getProperty(key:String):Object
Returns the object stored under the passed key
clear()
Clears all data in the persistence manager
flush()
Writes the stored information to disk. This is automatically run by the application on exit.
By using the apis above, various data can be stored in the persistence store. The default PersistenceManager that will ship with the framework will use a standard SharedObject as the data store. The shared object will be named "FXAppCache" and will exist in the application data storage directory on disk. SharedObjects use Adobe's AMF encoding scheme for storing objects. This means that the developer will need to be aware of the data restrictions and proper usage patterns when storing data.
First off, SharedObjects natively support all built-in basic types of the runtime, meaning objects of type Number
, String
, Array
, Vector.<Object>
, Object
, uint
, int
and Boolean
can be stored to disk without restriction. If a developer desires a custom class to be written to disk, this class will need to be registered with the runtime using flash.net.registerClassAlias()
before the persistence store is initialized or data is saved to it. If the developer fails to do this beforehand, the runtime with dispatch runtime errors related to the passed data, or will attempt to load the data as an untyped Object.
Complex data types, such as Class
, cannot be saved to a shared object and require the developer to convert the data to a supported object type, such as a String. In addition, private variables are not automatically written to the shared object as well. Both of these use cases can be resolved by implementing the flash.utils.IExternalizable interface on the custom object that holds the complex type. This interface expects an object to implement a writeExternal()
and readExternal()
method that are used to save and restore an object. Check the ActionScript 3 Reference for more information on IExternalizable.
Using the PersistenceManager, ViewNavigatorApplication will automatically save and restore application state information to the persistence store when the application is suspended and relaunched on device. ViewNavigatorApplication has a persistNavigatorState
property that when enabled, causes the application to automatically store application state information to the persistence store. The following keys will automatically be set through the PersistenceManager:
Property
Description
applicationVersion
The version of the application as described by the application.xml file.
navigatorState
The view state of the navigator. This by default will store the navigation stack of the main navigator
When the application is persisting its state, the main navigator will save the ordered list of Views it is currently managing and data object of those views. As described in #Persisting Data Between Application Sessions, the data object of a view must be AMF encodable.
Since some view data objects can be large and aren't necessarily in a proper format that can be written to file, a developer can override the serializeData()
and deserializePersistedData()
methods on View to create compatible and simpler objects that are written to disk. An example use case for this would be in an Employee database where each view's data object is a large XML file of data. Instead of writing the XML to disk, the developer may want to just write the id and a subset of the xml to disk, and retrieve the rest from the network in the background when the application relaunches. In this case, the developer could use the serialization apis on View to convert its data property object to something that only has an id and the name of the employee. Then, when deserializePersistedData() is called, the developer can display the Employee name in the UI while using the id to retrieve the rest of the employee information.
The persistNavigatorState
property is initially set to false, so the developer must manually enable this functionality in their main application class. Before the application attempts to save the navigator state to disk, the application will dispatch a "navigatorStateSaving" (FlexEvent.NAVIGATOR_STATE_SAVING
) event to notify the developer. The developer can prevent the application from persisting its state data by canceling this event. Similarily, ViewNavigatorApplication will dispatch an "navigatorStateLoading" (FlexEvent.NAVIGATOR_STATE_LOADING
) event before the persisted data is loaded. This can also be canceled to prevent this from occurring.
[[ warning title=u'Privacy Warning' ]]
The shared object used by PersistenceManager is not encrypted or protected. Persistence data will be stored in a human readable format that can easily be interpreted by another program or user. The developer should not persist sensitive information, such as user credentials, using this mechanism. The developer has the option of writing their own manager that provides better protection.
[[ /warning ]]
The PersistenceManager can be used when persistNavigatorState
is false by using the apis discussed above. When used in this matter, the properties stored are still automatically saved to disk. But, the persistence events (e.g, NAVIGATOR_STATE_SAVING) will not be dispatched and the data will not be automatically loaded at startup.
package spark.components.supportClasses
{
<a href="Exclude%28name%3D%26quot%3BcontrolBarContent%26quot%3B%2C%20kind%3D%26quot%3Bproperty%26quot%3B%29">Exclude(name="controlBarContent", kind="property")</a>
<a href="Exclude%28name%3D%26quot%3BcontrolBarGroup%26quot%3B%2C%20kind%3D%26quot%3Bproperty%26quot%3B%29">Exclude(name="controlBarGroup", kind="property")</a>
<a href="Exclude%28name%3D%26quot%3BcontrolBarLayout%26quot%3B%2C%20kind%3D%26quot%3Bproperty%26quot%3B%29">Exclude(name="controlBarLayout", kind="property")</a>
<a href="Exclude%28name%3D%26quot%3BcontrolBarVisible%26quot%3B%2C%20kind%3D%26quot%3Bproperty%26quot%3B%29">Exclude(name="controlBarVisible", kind="property")</a>
<a href="Exclude%28name%3D%26quot%3Blayout%26quot%3B%2C%20kind%3D%26quot%3Bproperty%26quot%3B%29">Exclude(name="layout", kind="property")</a>
<a href="Exclude%28name%3D%26quot%3BpreloaderChromeColor%26quot%3B%2C%20kind%3D%26quot%3Bproperty%26quot%3B%29">Exclude(name="preloaderChromeColor", kind="property")</a>
<a href="Exclude%28name%3D%26quot%3BbackgroundAlpha%26quot%3B%2C%20kind%3D%26quot%3Bstyle%26quot%3B%29">Exclude(name="backgroundAlpha", kind="style")</a>
//--------------------------------------
// Events
//--------------------------------------
/**
* A cancelable event that is dispatched before the application
* attempts to persist its information to disk. If preventDefault()
* is called on the event, the application will not persist anything
* to disk.
*/
<a href="Event%28name%3D%26quot%3BnavigatorStateSaving%26quot%3B%2C%20type%3D%26quot%3Bmx.events.FlexEvent%26quot%3B%29">Event(name="navigatorStateSaving", type="mx.events.FlexEvent")</a>
/**
* A cancelable event that is dispatched before the application
* restores its state from disk. If preventDefault() is called
* on the event object, the application will not restore its state
* but start up normally.
*/
<a href="Event%28name%3D%26quot%3BnavigatorStateLoading%26quot%3B%2C%20type%3D%26quot%3Bmx.events.FlexEvent%26quot%3B%29">Event(name="navigatorStateLoading", type="mx.events.FlexEvent")</a>
/**
* The ViewNavigatorApplicationBase class is the base application class
* subclassed by all Flex mobile application objects. This class
* is responsible for sets up the application infrastructure that
* the manages application persistence, the view navigation model,
* and the device integration hooks.
*/
public class ViewNavigatorApplicationBase extends Application
{
//--------------------------------------------------------------------------
//
// Skin Parts
//
//--------------------------------------------------------------------------
<a href="SkinPart%28required%3D%26quot%3Bfalse%26quot%3B%29">SkinPart(required="false")</a>
/**
* Dynamic skin part that defines the ViewMenu used to display the
* view menu when the menu button is pressed. The default skin uses
* a factory that generates an ViewMenu instance.
*/
public var viewMenu:IFactory;
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* The persistenceManager for the application. The persistence
* manager is automatically created on demand when accessed for the
* first time. Override the <code>createPersistenceManager()</code>
* method to change the type of persistence manager that is created.
*
* <p>The persistence manager will automatically save and restore
* the main navigator's persistence stack if the
* <code>persistNavigatorState</code> flag is set to true. Data stored
* in the persistence manager will automatically be flushed to disk
* when the application is suspended or exited.</p>
*
* <p>The default implementation of the persistence manager uses
* a shared object as it's backing data store. All information that is
* saved to this object must adhere to flash AMF rules for object encoding.
* This means that custom classes will need to be registered through the use
* of <code>flash.net.registerClassAlias</code></p>
*
* @default Instance of a spark.core.managers.PersistenceManager
*
* @langversion 3.0
* @playerversion Flash 10.1
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function get persistenceManager():IPersistenceManager;
/**
* Toggles the application session caching feature for the application. When
* enabled, the application will automatically save the main navigator's view
* data and navigation history to the persistence manager. When the application
* is relaunched, this data will automatically be read from the persistence store
* and applied to the application's navigator.
*
* <p>When enabled, the version of the application
* generated will also be added to the persistence object. This can be
* accessed by using the persistence manager's <code>getProperty()</code> method
* using either the <code>applicationVersion</code> key.</p>
*
* <p>When the persistence object is being created, the application will dispatch
* a cancelable <code>FlexEvent.APPLICATION_PERSISTING</code> event when the process
* begins and a <code>FlexEvent.APPLICATION_PERSIST</code> event when it completes.
* If the APPLICATION_PERSISTING event is canceled, the persistence object is not created.
* Similarily, when this information is being restored to the application, a cancelable
* <code>FlexEvent.APPLICATION_RESTORING</code> is dispatched followed by a
* <code>FlexEvent.APPLICATION_RESTORE</code> event. Canceling the APPLICATION_RESTORING
* event will prevent the navigation data from being restored.</p>
*
* <p>The <code>persistNavigatorState</code> flag must be set to true before
* the application initializes itself for the navigator's state to be automatically
* restored.</p>
*
* @langversion 3.0
* @playerversion Flash 10.1
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function get persistNavigatorState():Boolean;
public function set persistNavigatorState(value:Boolean):void;
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* This method is called when the application is invoked by the
* OS. This method is called in response to a InvokeEvent.INVOKE
* event.
*
* @param event The InvokeEvent object
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function invokeHandler(event:InvokeEvent):void
{
}
/**
* This method is called when the application is exiting or being
* sent to the background by the OS. If <code>persistNavigatorState</code>
* is set to true, the application will begin the state saving process
* here.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function deactivateHandler(event:Event):void
/**
* This method is called when the Application's hardware back key is pressed
* by the user.
*
* @param event The keyboard event
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function backKeyUpHandler(event:KeyboardEvent):void
/**
* Called when the menu key is pressed. By default, this opens or closes
* the ViewMenu.
*
* @param event The keyboard event
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function menuKeyUpHandler(event:KeyboardEvent):void
/**
* Method is responsible for create the persistence manager for the application.
* This method will automatically be called when the persistence manager is
* accessed for the first time or if the <code>persistNavigatorState</code> flag
* is set to true on the application.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function createPersistenceManager():IPersistenceManager
/**
* Responsible for persisting the application state to the persistence manager.
* This method is automatically called when <code>persistNavigatorState</code>
* is set to true. By default, this method will save the version of the
* application to the "applicationVersion" key.
*
* <p>This method will only be called if the <code>FlexEvent.NAVIGATOR_STATE_SAVING</code>
* event is not canceled.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function saveNavigatorState():void
/**
* Responsible for restoring the application's state when the
* <code>persistNavigatorState</code> flag is set to true.
*
* <p>This method will only be called if the <code>FlexEvent.NAVIGATOR_STATE_LOADING</code>
* event is not canceled.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
protected function loadNavigatorState():void
}
}
package spark.components
{
<a href="DefaultProperty%28%26quot%3BnavigationStack%26quot%3B%29">DefaultProperty("navigationStack")</a>
/**
* The main application class used for a mobile application. This application
* supports a single navigation stack that is provided through a ViewNavigator.
* the developer can dispatch navigation operation on the application by
* accessing the navigator property and calling the desired operation on
* the view navigator.
*/
public class ViewNavigatorApplication extends ViewNavigatorApplicationBase
{
//--------------------------------------------------------------------------
//
// Skin Parts
//
//--------------------------------------------------------------------------
/**
* The main navigator of the application.
*/
<a href="Bindable">Bindable</a>
<a href="SkinPart%28required%3D%26quot%3Bfalse%26quot%3B%29">SkinPart(required="false")</a>
public var navigator:ViewNavigator;
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* Provides access to the main navigator's actionBar
* if one exists. This property will only be valid after the
* navigator has been added to the display list.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function get actionBar():ActionBar
/**
* This property is the object to use to initialize the first view
* of the stack.
*/
public function get firstView():Class;
public function set firstView(value:Class):void;
/**
* This is the initialization data to pass to the
* root screen when it is created.
*/
public function get firstViewData():Object;
public function set firstViewData(value:Object):void;
//--------------------------------------------------------------------------
//
// UI Template Properties
//
//--------------------------------------------------------------------------
<a href="ArrayElementType%28%26quot%3Bmx.core.IVisualElement%26quot%3B%29">ArrayElementType("mx.core.IVisualElement")</a>
/**
* Array of visual elements that are used as the ActionBar's
* actionContent when this view is active.
*
* @default null
*/
public function get actionContent():Array;
public function set actionContent(value:Array):void;
/**
* Layout for the ActionBar's action content group.
*
* @default null
*/
public function get actionLayout():LayoutBase;
public function set actionLayout(value:LayoutBase):void;
<a href="ArrayElementType%28%26quot%3Bmx.core.IVisualElement%26quot%3B%29">ArrayElementType("mx.core.IVisualElement")</a>
/**
* Array of visual elements that are used as the ActionBar's
* navigationContent when this view is active.
*
* @default null
*/
public function get navigationContent():Array;
public function set navigationContent(value:Array):void;
/**
* Layout for the ActionBar navigation content group.
*
* @default null
*/
public function get navigationLayout():LayoutBase;
public function set navigationLayout(value:LayoutBase):void;
<a href="Bindable">Bindable</a>
/**
*
*/
public function get title():String;
public function set title(value:String):void;
<a href="ArrayElementType%28%26quot%3Bmx.core.IVisualElement%26quot%3B%29">ArrayElementType("mx.core.IVisualElement")</a>
/**
* Array of visual elements that are used as the ActionBar's
* titleContent when this view is active.
*
* @default null
*/
public function get titleContent():Array;
public function set titleContent(value:Array):void;
/**
* Layout for the ActionBar's titleContent group.
*
* @default null
*/
public function get titleLayout():LayoutBase;
public function set titleLayout(value:LayoutBase):void;
}
}
package spark.core.managers
{
/**
* IPersistenceManager defines the interface that all persistence
* managers must follow. These objects are responsible for
* persisting data between application sessions.
*/
public interface IPersistenceManager
{
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Clears all the data that is being stored by the persistence
* manager.
*/
function clear():void;
/**
* Flushes the data being managed by the persistence manager to
* disk or another external storage file.
*
* @return
*/
function save():Boolean;
/**
* Initializes the persistence manager.
*
* @return
*/
function load():Boolean;
/**
* Returns the value of a property stored in the persistence manager.
*
* @param key The property key
*/
function getProperty(key:String):Object;
/**
* Stores a value in the persistence manager.
*
* @param key The key to use to store the value
* @param value The value object to store
*/
function setProperty(key:String, value:Object):void;
}
}
package spark.core.managers
{
public class PersistenceManager implements IPersistenceManager
{
// See IPersistenceManager for apis
}
}
These methods will be added to ViewNavigator to support session persistence
class ViewNavigatorBase extends SkinnableContainer
{
/**
* This method is responsible for serializing all data related to
* the navigator's children into an object that can be saved
* by the persistence manager. This object will be sent to the
* restoreViewData method when the navigator is reinstantiated.
*
* @return The object that represents the navigators state
*/
public function saveViewData():Object;
/**
* This method is responsible for restoring the navigator's view
* data based on the object that is passed in.
*
* @param value The saved object that should be used to restore
* the navigators state
*/
public function loadViewData(value:Object):void;
}
These methods will be added to View to support session persistence.
class View extends Group implements IDataRenderer
{
/**
* Deserializes the data object that this view previous persisted
* when the application's session has been restored.
*
* By default, this method will set the passed value as the
* data property of the view.
*
* @return
*/
public function deserializeData(value:Object):void;
/**
* Serializes the data object into something that can be properly
* written to file or a shared object.
*
* By default, this method will return the data property of the
* view.
*
* @return The serialized object
*/
public function serializeData():Object;
}
The following example shows how to set up a mobile application that keeps track of a series of colored views. The user can click the various button to add views of a color type to the navigation stack. The view history is remembered, and when the back button is pressed, the user is returned to the previously visible color. Back button integration, orientation support, and automatic application state persistence are all supported by the application without the developer needing to add additional code.
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
persistNavigatorState="true"
firstView="ColorView"
firstViewData="0xFF0000"/>
<!-- No visual children can exist inside a mobile application tag -->
</s:ViewNavigatorApplication>
ColorView.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<!-- Set the background color to the color stored in the data property -->
<s:Rect left="0" right="0" top="0" bottom="0">
<s:fill>
<s:SolidColor color="{data}"/>
</s:fill>
</s:Rect>
<s:VGroup>
<s:Button label="Push Red" click="navigator.pushView(ColorView, 0xFF0000)"/>
<s:Button label="Push Green" click="navigator.pushView(ColorView, 0x00FF00)"/>
<s:Button label="Push Blue" click="navigator.pushView(ColorView, 0x0000FF)"/>
</s:VGroup>
</s:View>
Wiki: Flex 4.5
Wiki: Mobile ActionBar
Wiki: TabbedViewNavigator and TabbedViewNavigatorApplication
Wiki: View and ViewNavigator
Wiki: ViewMenu Spec