DLG Software


Application development

  with JavaScript, Flex, and AIR



UPDATE:   This primer is for Hero, the prerelease of Flex 4.5. For a version updated for Flex 4.5 see my Primer on Mobile App Development with Flex 4.5.

Introduction

This primer provides an overview of mobile application development using Hero, the preview release of Flex 4.5. It includes some information specific to Android.

Note: Since this primer focuses on using Flex/Spark to develop mobile apps much of its content will not apply to ActionScript-only mobile projects

While this primer includes links to numerous resources (blog posts, docs, books) one Adobe doc stands out so I'll highlight it at the start. Developing Mobile Applications with ADOBE FLEX HERO is an in-depth developer guide and is probably the definitive resource on the topic (link provides access to online and pdf versions).

Developer guides are great but we always need ASDoc, so here's Hero's: http://help.adobe.com/​en_US/FlashPlatform/beta/reference/​actionscript/3/index.html?filter_flex=4.5​&filter_flashplayer=10.1&filter_air=2.5

A bit about Burrito

To develop Hero apps you'll want Burrito, the preview release of Flash Builder 4.5. So far I haven't seen a lot of changes from Flash Builder 4 except for the new features to support mobile app development (well, there's also the bidirectional Catalyst stuff, but I haven't played with that).

As for Burrito installation, I don't have any personal caveats or cautions because my install was straightforward — I had not a single problem getting this up and running (thank you Adobe!).

Here are some quick points on installation/config:

  • Burrito won't conflict with an existing Flash Builder installation; you can install Burrito and not have it wreak havoc on your existing FB install (at least that's what Adobe claims, and it was my experience, though this is beta software, so your mileage may vary)
  • Burrito includes Hero (Flex 4.5), in fact that's the default sdk
  • Burrito's default value for workspace shouldn't whack any existing workspaces (default Burrito workspace dir name is 'Adobe Flash Builder Burrito Preview' created under your users directory)
  • The Burrito release notes state that you should not point Burrito to an existing (pre-Burrito) workspace
  • MS Win users, before you can use Burrito to deploy an app to your phone you need to install a USB driver for your phone. Burrito itself includes a link with info on this — go to the pulldown menu Run / Run configurations… and next to the "Launch Method" option's "On Device" radio button there's a link that addresses this config issue.

This primer won't cover Burrito features targeted for mobile dev, but I have links on this below.

Finally, remember, this is a preview release — I've found it to be very solid, but expect some quirks

Some Burrito resources:

Overview of Mobile Application Development using Hero

This section summarizes Hero features. Later sections drill into more detail.

Design for mobile

When creating mobile apps the traditional application developer must (to coin a phrase) think different. Some differences are obvious, some less so.

The most obvious difference between "traditional" Flex/AIR apps and mobile apps is real estate — not just screen size in pixels (Droid X is just 854x480, and that's more pixels than your average Android phone) but also physical screen size and the resultant pixel density. The skins for mobile apps account for mobile's greater pixel density by "sizing up". For example, the mobile skin for a Flex Button sets a button's height at about 70 pixels. While this is large on most PC screens (because they pack in fewer pixels per inch) it's just about right for most smartphones. But this affects screen design: when buttons are 70px then 854x480 starts looking even smaller.

Beyond sizing issues you also have some fundamental functionality differences. Different input methods is one: your desktop app that makes use of mouseOver won't work so well on a phone. And then there are the fun layout challenges that arise from re-orientation: most desktop apps never had to worry about users frequently flipping their screens between portrait and landscape. And then there's touch: it's a swipe-to-scroll world, so just kiss those old scrollBars good-bye...

Devnet has several excellent posts on this topic so let me mention a few here:

The Adobe Hero doc also covers some mobile-specific design issues — for example, see Chapter 7. And here is the Devnet page for Mobile and Devices.

Suffice to say that your UI design and app architecture for mobile will differ (sometimes significantly) from that of your traditional Flex apps. And this is where Hero helps you out — it includes many features that support/encourage good mobile design.

Hero

Hero provides functionality to support design patterns common in the mobile world. A lot of this involves data persistence and navigation. Hero provides a memory-efficient mechanism for navigating between views (View is another new Hero class, for now just think of it as a full-screen container). Hero also provides data persistence features that help you maintain state for individual views and even your entire application.

The root class of your Flex/AIR Mobile app will be Spark's new MobileApplication class, not Application or WindowedApplication.

In addition to MobileApplication there is a TabbedMobileApplication class. I don't cover it here because the Hero preview release doc says the following on pg 46:

"Note: Mobile applications with multiple sections are not supported in this release. Therefore, do not use TabbedMobileApplication or TabbedViewNavigator on your applications."

Obviously this is likely to change with the final release of Flex 4.5.

When you create a mobile app (File/New/Flex Mobile Application) Burrito creates both your application root class (an instance of Spark's MobileApplication class) and a default home screen (an instance of Spark's View class). You define your UI in the views, not in your root class (though you can put code in the root class).

During development you create the views you need (File/New/MXML Component) and within those view containers you define your UI. Then at runtime you navigate between views using features of the new ViewNavigator class. MobileApplication creates an instance of ViewNavigator for you and it is available to all views through their navigator property. The ViewNavigator itself creates an ActionBar instance that is shared by all views. This actionBar is basically a container that can appear docked above your view and is commonly used for title or message text and option controls.

Here's a crude representation of the relationship between MobileApplication, ViewNavigator, ActionBar, and View:

MobileApplication creates the shared ViewNavigator instance  

ViewNavigator manages all Views and an ActionBar

Views     ActionBar
ViewNavigator can manage multiple views
but only one is active (in memory) at a time

As for defining your UI, for the preview release Adobe recommends use of a limited Spark component set (currently only a subset of Spark components have been given mobile skins). These mobile-ready controls are listed in "Developing Mobile Applications with ADOBE® FLEX HERO" (see here or page 4 of the pdf).

As for using MX controls in your UI, in general you should not use any mx controls in a MobileApplication project. In fact, by default the mx controls are not even in the path (no xmlns for mx). However, Adobe does say that if you want to include charts in your mobile app you can use the mx datavisualization controls. Again, for details see here or page 4 of the PDF).

A mobile app's navigation between views is similar to that of mx:ViewStack, where you navigate between child containers with a single container active (visible) at a time. One big difference is persistence: a ViewStacks's children persist once they've been created, but ViewNavigator keeps only one view in memory at a time. That is, garbage collection for views is essentially immediate — by default as soon as you move off a view it's a candidate for garbage collection. If you navigate back to that view you'll get a completely new instance. This helps minimize your app's memory footprint.

When you are coding a mobile app think memory, memory, memory. The threshold for encountering memory problems is much lower on a phone than on a PC. Remember, most phones have very limited RAM (Droid X = 512 MB and many phones have less). If you use too much memory Android may kill your app (see my post AIR for Android memory issue with large images on this). If your app is in background and Android needs more memory it can also kill your app (another reason you should maintain view and app state).

Ok, that's some basics, here are some resources, and then we'll drill down a level.

Resources: Intro to Hero

A good intro into Hero is the new Tour de Flex Mobile. Install it from the Android marketplace and see this stuff in action, with source code provided.

Here are some links to Hero overview pages and videos

ViewNavigator, ActionBar, and Views

Every MobileApplication has a ViewNavigator instance that provides much of your app's mobile-specific functionality. In addition to creating views and providing view navigation the navigator provides an optional and configurable ActionBar that can appear atop your view and can contain UI controls.


 
To interactively explore the parts of the Hero mobile app I recommend installing Tour de Flex Mobile on your phone and then using its "Mobile App Anatomy" option.

Below is a screencap that shows the layout of a basic mobile app.


singleFrame.png  


Action bar is created/managed by ViewNavigator. It is optional and customizable. You can have a global actionBar that is modified by individual views
  • titleContent area is at center, here with text value "StageWebView". Set the text value using view's title property or populate this area with components
  • navigationContent area is left of title, here a "Back"button
  • actionContent area is right of title, here a "Source" button

This view's content area is completely filled with a StageWebView instance, but as with any container you can populate it with whatever components you need. View is a subclass of Group.

View anatomy (Tour de Flex Mobile "StageWebView" example)

An ActionBar has three parts: a titleContent area, a navigationContent area (left of title area)   and an actionContent area (right of title area). You have total control over what appears in these areas through properties of the View class. For example, View.title sets the text in the titleContent area. But you can also put your own components in this area using the titleContent property. See Hero doc's section "Spark ActionBar control" for details and several usage examples. Remember, you have total control over what displays in the actionBar (or whether the actionBar displays at all).

As noted above, a view is basically a container where you place your user interface controls and the code that drives them. What makes this container different from other Spark containers like Group and SkinnableContainer is that View has properties and methods specific to the Hero mobile architecture. In essence it's a "ViewNavigator-aware" container.

While a View is a container, in some ways it's like a very specific type of container, an ItemRenderer. In fact each view has a data property just like an item renderer. In the case of a view, it's up to you to populate that data property. We'll cover this in a minute, but first let's take a moment to consider the lifecycle of a view.

Here is a nice summary of View from the Adobe View+ViewNavigator design doc : "A view can be thought of as a standard Flex 4 ItemRenderer with an integrated data model and additional functionality that allows a view to provide contextual information about itself to external components (such as ActionBar). A view will have a data property that can be used to represent the content and the state of the view. This object is automatically serialized, persisted and restored by the view's navigator as the view is activated and deactivated"

To keep memory use down ViewNavigator keeps only the currently displaying view in memory. In other words, when you navigate away from a view it is immediately eligible for garbage collection. So, if you navigate from ViewA to ViewB, by the time ViewB is displayed it no longer has ViewA available for reference (presuming you have no pointers to ViewA that inhibit its garbage collection). An obvious implication of this design is that time you can't directly set event listeners from one view to another; or have one view directly read another's data. Note that this auto-destruct behavior for inactive views is default. You can override it using View's destructionPolicy property but in general you shouldn't — remember: memory, memory, memory!

Although views are destroyed, their data persists — that is, Flex stores/restores the contents of each view's data property each time it's destroyed/instantiated. So, the contract here is that when you return to a view the previous contents of its data property will be available to you; your code can count on the data property being populated early in the instantiation process (before the ADD event fires). How might you use this view data persistence mechanism? Well, you could use it to restore your view to a previous state. More on this in the next section.

The View class data property

The View class defines a property named data which is of type Object. The very first time a view is instantiated its data property has a value of null (well, unless you've implemented application-level persistence, but we won't cover that here). So, your app will generally include a check to see if your view's data property is null and, if it is, creates the data structure you want to work with. Something like this:

	if (data==null)  
	{
		data = new Object() ;	
		data.someText = "howdy!" ; 
		data.someNumber = 1234   ;
	}
	else
	{
		// do something with contents of data property,
		// e.g., initialize your view with data values
	}  

You can populate a view's data property with whatever data you want. The thing about the data property is that once it's populated it stays that way — ViewNavigator will persist the contents of a view's data property whenever the view is destroyed (e.g, when you navigate to a different view) and it will restore those contents if your view is reinstantiated.

Because a view's data persists during an app's session (and potentially across sessions) one use of a view's data property is to maintain state. How? That's up to you, the framework just provides a persistence mechanism. But clearly this isn't rocket science. Just fill data with whatever you need to restore state, and to complement this you include instantiation-time code that uses the contents of data to initialize fields to previous values, maybe makes use of Flex 4 states to restore appearance, etc.

It's worth emphasizing that saving and restoring state is an important part of mobile app design. Remember, you're on a phone, and users sometimes navigate away from your app. If they're gone long enough your app may be killed by the OS. When mobile users eventually return to an app they generally expect to pick up right where they left off. It's your job to make this happen. Of course, in some apps saving state isn't important. In that case don't use the data property for this purpose. Again, how you use the data property is up to you.

I won't cover Hero's session persistence features (enabled through the sessionCachingEnabled property of the MobileApplication and TabbedMobileApplication classes). To read more about this see the Hero doc's sections titled "Session persistence" and "Data Persistence". Of course, you can also roll your own persistence mechanism — a good place for using SQLite, which is integrated into the AIR runtime. See Jon Campos' post on this.

So far I've addressed using the data property to save state. But it can also function like the data property of a Flex ItemRenderer. That is, you can use it to pass in data you want your view to render. We'll cover this in a moment, but before that we need to consider navigation between views in a bit more detail. First, here are some resources:

Resources: MobileApp Views and ViewNavigator

For a diagram of a view's lifecycle including the firing order for events like VIEW_ACTIVATE and VIEW_DEACTIVATE see the section "The life cycle of the Spark ViewNavigator and View containers" in "Developing Mobile Applications with ADOBE® FLEX® HERO". It's also covered in the View design doc mentioned next.

Here is Adobe's design doc for View (and ViewNavigator), really interesting reading, though it's just a design doc so actual implementation sometimes varies from doc specifics (e.g., poppedViewReturnObject was renamed returnedObject, replaceView method was not implemented, etc.).

Also check out the ATV videos from Max 2010 (Develop), there are several related to mobile development.

And Mihai Corlan has many thoughtful posts on Flex, here's one on Hero.

View navigation

To navigate between views you can use the ViewNavigator class. MobileApplication creates a ViewNavigator instance at startup and makes it available to all views though their navigator property.

It can be useful to think of mobile view navigation as similar to mx:ViewStack, where you have multiple containers, one container is initially displayed, the containers can be displayed in an arbitrary order, but only one container is active (visible) at a time. However, a big difference between ViewStack and ViewNavigator is persistence: with ViewStack your child containers are created when you first navigate to them and after that they persist; with ViewNavigator each view is created every time you navigate to it and destroyed every time you navigate away from it (this is default behavior, you can modify it, for example if you have a view that takes a lot of time to create).

View navigation is done via stack push and pop operations. When your app starts up the Flex framework will display your home view. This is the view you've assigned to your MobileApplication's firstView property. When you create a MobileApplication in Burrito (File / New / Flex Mobile Project) an initial view is created for you in a views package. By default it will be named [your-project-name]+"Home". From this home view you can display another view through a push operation (navigator.pushView(MyOtherView); ). More views can be added to the stack with more push operations.

The navigation stack operations available are: pushView(), popView(), popToFirstView(), popAll(). To these methods you pass the view you wish to display. Note that you pass the view class name, not an instance of the view class. This is because the ViewNavigator is responsible for the instantiation of views (via a class factory) so you don't instantiate them yourself (so, you do not do: var myViewInstance:MyView = new MyView();). See ViewNavigator's ASDoc entry for details.

Let's consider a simple example where a home view uses another view to display detail information (image from page 10 of Developing Mobile Applications with ADOBE® FLEX® HERO).


singleFrame.png

  views.ListView                                         views.DetailsView

A scenario for the above could be:

  1. Your MobileApplication has the assignment firstView="views.ListView" so at application startup an instance of the ListView class is created and displayed
  2. The view ListView is basically just a selection list. It responds to a user selection by navigating to DetailsView, which lives in the default views package. So, your call might be:
    navigator.pushView(​views.DetailsView)
  3. When DetailsView is pushed onto the stack it is instantiated by the ViewNavigator and added to the display list. At the same time, our ListView view has been removed from the display list and is now eligible for garbage collection (but the contents of its data property have been saved away, ready for recall in case we re-instantiate ListView)
  4. DetailsView can either display yet another view by executing its own navigator.pushView OR (as shown in the diagram) it can return to ListView with a call to navigator.popView().
  5. When the popView executes ViewNavigator just refers to its stack to get the name of the last displayed view class, then it instantiates that view (note that we get a completely new instance) and then it populates the view's data property with the data saved away in step 3.

Of course, the example above is incomplete since it doesn't consider how the detail view knew whose details to display (in this case, info on Lauren Fisher). We'll consider passing data between views in the next section.

Note that in Hero apps the Android back button takes you back to the previous view (i.e., it executes a popView()). This is Hero built-in behavior implemented by the ViewNavigator class — you do not need to do anything to enable this native Android behavior. I'm working on a Hero tips post related to this. For now just let me mention that you can't inhibit this native behavior by listening for an Android back button press and then simply stopping the popView through preventDefault() — doesn't work in Hero.


Resources: View Navigation

Passing Data between views

As your app navigates between views you will, of course, need to pass information between your views. As with many things in Flex, there are several ways to skin this cat. Mostly we'll focus here on the built-in mechanisms provided by Flex.

During view navigation you can pass data "forward" (i.e., when you do a pushView) and "backward" (e.g., when you do a popView) through features of ViewNavigator. How you do this varies depending on whether you are pushing or popping a view.

pushView

To pass data into a view you can use pushView's second parameter to specify a data object that will be passed to the new view. The new view will receive this through its data property. Here are some examples.

Example 1 - passing a property value of a UI component, in this case a list's selected item:

     navigator.pushView(views.DetailView,myList.selectedItem) ;

Example 2 — creating/passing an object:

     var myObj:Object = { 
		user:username , 
		numSelections:2 , 
		msgText:"Choose 2 values" };  
	navigator.pushView(views.SelectionList, myObj) ; 

Example 3 - passing the view's data property:

	data.listMessageText = "Select a customer" ; 
	data.listDataProvider = model.customerIDs ; 
	navigator.pushView(views.SelectionList,data) ;    

When you pass data into a view it is assigned to the view's data property. In that way a view is a bit like a Flex ItemRenderer. That is, upon instantiation its data property is populated with the data to be rendered and you use this to populate your view components (e.g., msgline.text=data.msgText). Note that Hero also includes "real" mobile-optimized renderers like MobileItemRenderer but I won't be covering them in this version of the primer.

popView

When you want to return data on a popView() the mechanism for passing data is different than with pushView — there is no popView parameter for passing data. However, you can return data to the previous view through the View class returnedObject property. You do this by overriding the createReturnObject method and, in this override, creating the data object you want to pass back. Then in the popped-to view you retrieve the returned data from the returnedObject property. So, a 2-step process:

1. The view that will return data has an override of its createReturnObject method. This method is used to create an object that will be passed back to the previous view. It executes whenever the view is popped. Here's an example:

 override public function createReturnObject():Object 
 {				
   var listViewReturnObject:Object = new Object();
   if (list.selectedItem) 
   {
     // pass back selected value, here we just return its label text
     listViewReturnObject.lastSelectedItemValue = list.selectedItem.label ;
   }
   return listViewReturnObject;			
 } 

2. In the view you've popped to you include a creation-time check of the returnedObject property. If it's not null then the assumption is that you just got popped to, and the "popper" has passed you some data. Obviously how you handle that returned object is up to you.

  if (returnedObject != null) 
 {
   // process the data object you passed back...
   msgline.text="You selected "+returnedObject.lastSelectedItemValue ; 
 }
 

As an alternative to using the returnedObject property you could share data between views through a persistent data structure that's available to both views. One view can modify the data and then when your app navigates to another view the data is still there for it to read. One way to do this is through a view's data property, since it's persistent. Something like:

  1. ViewA creates some data structure (e.g., Object) and assigns it to its data property
  2. ViewA then calls ViewB, and it passes along a reference to its data property
  3. ViewB does whatever it does. This includes updating/adding values in the the data object it was passed
  4. Eventually ViewB calls popView, thus returning control to ViewA
  5. ViewA can now retrieve the updated/added data from its own data property

As mentioned above, this works because the view's data property is persistent.

Using a model

Of course, there are other (and arguably better) ways to persist data across views. You might want to consider using a model to store your data (model as in Model-View-Controller). Since mobile apps are by nature fairly simple you may even want to use a Singleton ModelLocator (basically, the same approach used by Cairngorm and PureMVC). This lets you centralize data so it's available to all views. Just instantiate it in your app's root class (the one with the MobileApplication root tag) and it will persist even as your individual views come and go. A downside of this is that each view becomes tightly coupled to that ModelLocator, since they must must "know about" (have dependency on) that ModelLocator to read and write this data.

Resources: Passing Data between views

Conclusion

Developing mobile apps is a big topic and this post barely scratches the surface (hey, where's info on touch and gesture support? MobileItemRenderer? using geolocation?). Still, hopefully some of this has been useful to get you started with Hero. I'm also working on a post with Hero tips and traps, for now I'll just tack on a few sample tips below:

  • Since memory is critical on mobile you need to keep an eye on it. How? If you have Flash Builder Premium then just use the profiler. If you don't then you can check your app's memory use through System.privateMemory.
  • Hero lets you interface with OS apps (e.g., invoking the Droid's camera, cameraRoll, the dialer, etc). When you invoke one of these apps your app goes into background mode and a DEACTIVATE event will fire. If control returns to your app an ACTIVATE event will fire. For example, if you invoke CameraRoll then when the user selects an image an ACTIVATE event will fire as your app returns to foreground. Keep this behavior in mind if you are thinking of using those events to trigger view initialize and cleanup activities.
  • Hero includes nice view transitions but they can get flaky if you do other processing while the transition is executing. You can always kill transitions with ViewNavigator's transitionsEnabled property. Or you can just wait until the transition has completed by listening for the transitionEnd (transitions are under contruction, there appears to be no CONST available for this event so you'll have to use the string value). Example: this.navigator.addEventListener(​"transitionEnd",initView) ;
  • If you don't like the title text on the ActionBar you can easily replace it or style it. Here's a replacement that drops down the font size so the text can better be used as a messageline:
	<s:titleContent>
	  <s:Label id="msgText" text="howdy" color="yellow"
	     fontSize="24" verticalAlign="middle" width="100%"/>
	</s:titleContent>      
  

More Flex/AIR Mobile Resources

O'Reilly is about to publish a book on developing AIR apps for Android, "Developing Android Applications with Adobe AIR". It's an excellent intro to the topic, though be forewarned that it doesn't spend a lot of time on Hero/Flex. You can order the Rough Cuts version now.

Adobe TV has several Max 2010 videos on Mobile development. Here's your start point: http://tv.adobe.com/show/max-2010-develop/

I'll repeat something mentioned above: If you are a Lynda subscriber there's a video course titled Flex "Hero" and Flash Builder "Burrito" Beta Preview

Some links that didn't fit in above: