29 November 2011
This article builds upon basic knowledge of Flash Builder 4, Flex SDK 4, and the Spark component set. Understanding of classic MCV (Model Controller View) or MVP (Model View Presenter) design patterns will prove useful.
Just a year after Flash Builder 4 and Flex 4 SDK were released, new versions are available with Flash Builder 4.5 and Flex 4.5 SDK! The main focus for Flex 4.5 SDK and Flash Builder 4.5 is the ability to build mobile applications that target the Google Android, Blackberry Tablet OS, and Apple iOS operating systems. Additionally, Flex 4.5 SDK introduces new Spark components and improvements for large application development while Flash Builder 4.5 introduces dozens of new coding productivity features for faster ActionScript and MXML development. To learn more about what is new and improved in Flex 4.5 SDK, check out Deepa Subramaniam’s article. And to learn about what is new in Flash Builder 4.5, including new developer-oriented features as well as new workflows with Flash Catalyst CS 5.5, check out Andrew Shorten’s article. If you want to learn specifically about the new mobile capabilities in both Flex 4.5 SDK and Flash Builder 4.5, read Narciso Jaramillo’s overview article.
In this article, we will cover how to build applications that target both traditional web and mobile deployment. We will talk about three reference applications we built where each application runs in the browser as a traditional web application as well as on mobile devices. These three applications are the Shopping Cart, Expense Tracker and Sales Dashboard applications. We will cover specific considerations when building a Flex application for mobile and tablet devices as well as web. Additionally, We will cover how my team architected the applications to share code between the web and device projects. And finally, we will talk about performance considerations one should think about when building applications for all form factors.
While all the project types available in Flash Builder 4 are supported, Flash Builder 4.5 introduces additional Flex project types including Flex Mobile projects and ActionScript Mobile projects. These mobile projects are attuned to mobile application development. Flex Mobile projects understand the mobile "safe" Flex components usable on mobile devices. Additionally, Flash Builder 4.5 gives you help when creating a new mobile project, regardless if it's a Flex Mobile or ActionScript Mobile project. To create a new Flex Mobile project go to File > New > Flex Mobile Project. You'll see that Flash Builder helps walk you through how to create and configure a new mobile project, including its name and the type of mobile application you want to build. The Shopping Cart, Expense Tracker, and Sales Dashboard mobile applications all use the View-based application type. This means each view of the application is governed by its own View class and all the views are controlled by a ViewNavigatorApplication. The Shopping Cart and Expense Tracker tablet applications are also controlled by the ViewNavigatorApplication. However, the Dashboard tablet application is a standard AIR Application that uses a SplitViewNavigator to manage its views.
Flash Builder 4.5 will help create stub views for your view-based application. You can then add in subsequent views for your application. Each stub view derives from the spark.components.View class. Views understand how to display data and inject information into the Action Bar. An Action Bar is the navigational UI at the top of each application. This provides contextual information about the current view, including the title of the current view and action buttons that can navigate the user to particular places within the application.
The Shopping Cart mobile project organizes all of its child views in the com.adobe.mobileshoppingcart.view package. There you can see the MXML classes that creates the UI for each subsequent view in the Shopping Cart mobile application. For example, CartView.mxml is the checkout view once the user has chosen an item to purchase or ItemDetailsView is the detail view for individual items (see Figure 1).
Flash Builder 4.5 gives you all of the workflows you need to develop applications for a variety of project targets, including web for deployment with Adobe Flash Player, or desktop, or tablet, or mobile devices for deployment with Adobe AIR. For our team, we decided to use an application architecture when building the web and device versions of the Shopping Cart, Expense Tracker, and Sales Dashboard applications. This application architecture worked very well with regards to organizing code across the development team as well as keeping UI code separate from service layer code. Additionally, this architecture let us share code between our web and device projects. (Note: it is not necessary to use an application architecture to share code between web and mobile projects, but in our case with a distributed development team, an application architecture proved beneficial).
The architecture we chose is loosely based on a classic Model View Presenter (MVP) architecture. MVP uses passive views and takes advantage of a formal controller to pass state and UI information between views. By keeping all logic code out of the view files, my team and I were able to reuse the core application code in multiple projects.
The core application code that will be shared between multiple projects, in our case between the web projects and the mobile projects, is all contained in a Flex Library Project (FXPL). For example, MobileShoppingCart.fxp, ShoppingCartTablet.fxp, and ShoppingCartWeb.fxp all link in ShoppingCartLib.fxpl. ShoppingCartLib.fxpl contains all of the shared code relevant between the web and device versions, including the service layer and utility classes. Similarly, DashboardMobile.fxp, DashboardTablet.fxp and DashboardWeb.fxp all link in DashboardLib.fxpl and DashboardChartLib.fxpl. These FXPL's contain the shared code for handling the charting components and data management in the Sales Dashboard web and device applications. And finally, CRUDMobile.fxp, CRUDTablet.fxp, and CRUDWeb.fxp link against the shared library project, CRUDLib.fxpl.
When using a Flex Library Project, the general rule of thumb is that the data models, controllers, services, events, and utility classes should all be included. Generally, the library project should not contain any UI-specific code unless its ok to share that UI across different form factors. It is the responsibility of the Flex Mobile project to add in the mobile-specific UI code as MobileShoppingCart.fxp does and the Flex project to add in the browser (or desktop)-specific UI code as ShoppingCartWeb.fxp does. This practice helps ensure good encapsulation and reuse of common code across different form factors.
The presenter's are the rock-stars of the application architecture. Each functional state of the application has a presenter class. Instances of presenters are injected into the view files, either through metadata injection with a framework like Swiz, references from a Singleton model, or passing the presenter in through the constructor. In the sample projects listed above, the instances of the presenters for the main classes are referenced from a Singleton model while the presenters for the item renderers are created on the fly in the controller class. For example, the ItemDetailsView.mxml class in MobileShoppingCart.fxp has a reference to a presenter variable in line 36. It is from this presenter object that the business logic of the application is referenced by the view. Similarly, the List components in each web and mobile application are displaying a list of presenter objects. The List control in MainView.mxml in MobileShoppingCart.fxp is displaying a list of items the user is viewing. These data items are presenter objects being displayed by the view.
All properties displayed by the view are held by the presenter. The presenter communicates to the views via events. This is why each presenter class extends EventDispatcher. Check out the ItemPresenter class contained in the ShoppingCartLib.fxpl project (com.adobe.shoppingcart.presenter). Notice how ItemPresenter extends EventDispatcher and dispatches events whenever something has changed. In this manner, the presenter exposes a public API of methods that the views can call on in order to display the UI appropriately.
The presenter holds an instance of an IEventDispatcher object, in this case the instance of the controller, that it uses to dispatch events. This is the way that the presenter communicates with the business logic portion of the application. The presenter does not ever hold an instance of a controller, or make function calls up the chain. To respect encapsulation the presenters only dispatch events. Events are the contract between the presenter and a controller.
The controller controls communication between the different parts of the application. Application state decisions are made in the controller. At application startup, an instance of the controller is created. In the sample projects check out the preinitalizeHandler in WebShoppingCart.mxml and MobileShoppingCart.mxml. This is where the controller is created for the web and mobile versions of the Shopping Cart application. The controller creates instances of the presenter objects and stores them in the model. Additionally, the controller sets all properties on the model.
The controller also listens for events from the presenters. When a presenter fires an event, for example, to change the current screen, it is the controller who handles the event. The controller then makes a logical decision on how the presenter's request should be handled. The controller may make a call into the service layer or set properties directly on the presenters.
Properties that need to be kept in sync across multiple presenters are sometimes cached in the model, but for the most part each presenter holds it's own state and properties. There is no reason that you cannot have the models hold state and broadcast state changes to the presenters as MVP dictates, however in my experience, it just add an extra layer of complexity without many gains.
On occasion I find the need for controller behavior to be different depending on the project target. In these cases, I extend the controller and override the methods that need custom implementation. This extended controller is the class that I instantiate during the main initialization for the specific project type.
The view code is often not shared between project types. Alternatively put, the Flex mobile project contains the mobile-specific UI and the Flex project contains the non-mobile-specific UI. This way, the user interface is fine-tuned for the specific form factor which the application is running on.
Create a new Flex or ActionScript project for each of the screen targets your application needs to support. Similar screen targets, like mobile phones and tablets, may be able to use the same project depending on your application's needs, though Flex does have support for creating UI specifically for smart phones versus tablets.
The view-specific UI code (MXML files, CSS stylesheets, assets like images and fonts) should be created in each of the projects. While most of the view code is created specifically for the form-factor the project is targeting, all the core application code can be shared. Each of the new views that you create in your projects will be able to communicate with the rest of the application via the presenter. Since no logic code is kept in the views, there is very little need to duplicate code in views between projects. Instead, you can simply bind to properties on the presenter and make method calls on the presenter in response to user gestures.
The model is used to store the instances of the presenters. The instances of the presenters are referenced from both the controller and the views. The model holds instances of the presenters so that both the controller and the view can have access to the same instance.
Views should never reference properties in the model. Instead, views should only know about their presenter (and perhaps a state enum or some such declaration). References to model objects directly from a view breaks the encapsulation pattern. Simply put, the only contract that a view should know about is that of the presenter.
If you are using a framework like Swiz you can simply inject the presenters into your views and forego holding them in the model. The Swiz framework creates and manages the instance of the presenter for you.
I strongly recommend using service delegates that are defined by an interface. This allows for easy swapping to a different service implementation without changing any other application code. This is especially powerful if you are developing against mock, or as of yet unfinished, services during the initial stage of application development.
In the context of the architecture we used, the controller holds instances of the service objects. The controller makes calls on the service objects and listens for responses. We use an AsyncToken as the service contract for listening to results; faults are very handy in this case. In CRUDTablet.fxp if you look at ExpenseItemsSQLLiteService.as, you can see how this approach let us easily switch to using SQLLite to store our data.
You may work with designers to come up with the look and feel and interaction patterns for the UI of your application, regardless if it's targeting web, mobile, tablet or desktop. Our team worked with designers to design each view, especially for the mobile and tablet projects. Our designers spent time considering how users will interact with the mobile or tablet device the application is running on, the screen size and density-per-inch for a variety of different devices and the navigation paradigms users are accustomed to when using mobile or tablet devices. With all this information, as well as with the conveniences Flex offers, we were able to settle upon a design that was both visually pleasing and easy to implement with Flex.
A good user experience designer and visual designer can take an application from OK to amazing. Good communication between designer and developer requires a balance of form and function which can result in an application that not only is easy to use but looks great and works great too! In my experience, many organizations confuse user experience design with visual design. Often times the role of a user experience designer is overlooked and that task falls to the visual designer, or the developer. The user experience designer spends time analyzing how the application should be interacted with, including the display and navigation of data and application state. In my experience, projects that have a dedicated designer or specialist focusing on the user experience results in better software
In our project, the web projects all had wireframes that were created by the visual designer in Adobe Illustrator CS5 or Adobe Fireworks CS5 . The wireframes were then converted into functional Flex code either through the use of Flash Catalyst CS 5.5 or the developer hand-craftng Spark skins for the Flex components based on the wireframe provided by the visual designer. Additionally, the Flash Builder Wireframe theme works very well for sketching out a simple UI for the application in the early stages. To learn more about how you can use Flash Builder 4.5 and Flash Catalyst CS 5.5 to develop skins and assets for your project, check out this article by Jacob Surber.
The skinning architecture introduced by Flex 4 makes creating custom views very easy, whether its for your mobile or web project. To learn about this new skinning architecture, called Spark, check out this overview article.
The Flex 4.5 SDK builds upon Spark for all of its mobile components and functionality. All of the components optimized for mobile use in Flex SDK 4.5 contain special mobile skins. For performance reasons, these skins are created in ActionScript. These mobile skins are lightweight and do not have as many exposed styles as the default Flex 4 skins. For most of the mobile projects, we created new skins in ActionScript 3 however we were able to use MXML skins in some places. The general rule of thumb is that MXML based skins for Flex Mobile projects is OK, especially when used sparingly. But if you start noticing performance problems, switch over to ActionScript-based skins to seek out more performance gains. Because tablets usually have faster processors we were able to use more MXML for the skins than we might for a phone app. For most of the Shopping Cart, Expense Tracker and Dashboard mobile projects, when creating new skins for mobile components, we extended the default mobile ActionScript skins as opposed to the default MXML skins.
Often times simply writing programmatic drawing code in skin files is the best way to translate the visual design to Flex. This may seem tedious at first, but after a short while it will be come second nature. This also means you have much better performance! In most cases manually drawing code in skins files results in much better looking skins then embedding assets. Even if you don't want to use pure-ActionScript for this, you can use FXG. In general, FXG is recommended for use in Flex mobile projects. Notice how most of the skins in the Shopping Cart mobile project are created with FXG. Skins created in this way are smaller and easier to maintain over the life of an application.
For art that cannot be easily recreated via FXG, it becomes necessary to use external assets. While Flex supports loading and embedding many types of assets, some formats tend to work better then others. For static vector assets, FXG is the best choice. For static bitmap graphics, JPG files tend to be the smallest and easiest to use. When possible, bitmap graphics with transparency should be recreated as vector artwork. This is a good performance-inducing tip. In general, encouraging visual designers to use less bitmap graphics is a good thing.
Data-aware controls are important and oft-used in Flex projects. In all of the mobile reference projects, Lists are used to display data and users interact with Lists in order to delve deeper into the application. Similarly, the web projects use Lists and other List-like components to display data and contextual information to the end user.
The Spark List component has been optimized for mobile use in the Flex 4.5 SDK. Additionally, a Spark DataGrid makes its debut with the Flex 4.5 SDK. In both cases, it's important to understand how to create high-performing item renderers for use by the component to display data. Item renderers are often the major culprit with slowing down the interactivity and smoothness of Lists and List-based components. In addition, you may want to avoid adding filters like DropShadow to a list because the whole list has to be cached as bitmap when scrolling. The following sections gives you tips on how to create performant item renderers for use with Spark Lists and Spark DataGrids.
An item renderer is a class defined to display the data bound to a List-based component. When scrolling a Spark List, the item renderers redraw very frequently. This redraw can sometimes slow down the feel of your application. Effort spent writing efficent and smart item renderers will greatly improve the scrolling experience of Lists in your mobile or non-mobile application.
In the Shopping Cart web project, we use several custom item renderers. Take a look at ItemPreviewListRenderer.mxml in the ShoppingCartWeb.fxp project. Notice that this item renderer does not have extraneous FXG elements, it does not make use of excessive data-binding, and it does not nest containers or Groups too much. These are all good tips for creating performant item renderers regardless if it’s for a mobile or non-mobile List.
The Spark List component has the property useVirtualLayout set to true by default. This means that the item renderers will be reused when new data items scroll into view. This is very helpful when displaying and navigating through a long list of data.
When an item renderer is created or recycled, the data property is set with the new item that needs to be displayed. In order to manage this setting of data, you need to override the setter for the data property. In ItemPreviewListRenderer.mxml, you will notice that the data property is actually an instance of a presenter object. When set, the data property is cast as an ItemPresenter and then set to the presenter class property. The visual components, in turn, are bound to properties in the presenter and make method calls on the presenter. This is a very powerful example of how presenters are used to encapsulate logic.
When developing the Shopping Cart mobile project, a significant amount of attention was paid to optimizing the item renderers used in each view that contained a Spark List component. The default Flex ItemRenderer class that you may be familiar using in web and desktop Flex projects is not recommended for use in Flex mobile projects. Instead, new item renderer classes are introduced which are specifically optimized for mobile. This includes LabelItemRenderer, a default mobile renderer for showing a line of text, and IconItemRenderer, a default mobile renderer for showing text and an image (see Figure 2).
The base class you should use when creating a simple text item renderer for a List component used in a Flex Mobile project is LabelItemRenderer. LableItemRenderer extends from UIComponent and has a much smaller footprint then ItemRenderer since ItemRenderer extends from Group and thus carries more weight. LabelItemRenderer is the default item renderer for the List component in a Mobile Flex Project. It renders a single text element as shown in the screenshot above. LabelItemRenderer inherits the labelField property set on the parenting List component and displays the text in a text element called label. The label is an instance of a StyleableTextField. StyleableTextField extends TextField and provides, as the name suggests, mechanisms to apply CSS styles to control the text display. While TLF text is great for use in web and desktop applications, TextField performs much better in mobile scenarios. TextField is especially useful in mobile applications when scrolling elements heavy with text.
Choose LabelItemRenderer for the fastest scrolling performance out of the box. When writing your own item renderers, subclass from LabelItemRenderer. In general, copy the practices and principles used in LabelItemRenderer, like programmatic code to handle measurement and layout and a sensitivity towards excessive use of data-binding.
IconItemRenderer extends from LabelItemRenderer. In addition to the text display provided by LabelItemRenderer, IconItemRenderer provides additional display elements, like:
The label element is the same as in LabelItemRenderer and displays the text bound to the renderer. The message display element is a secondary (and optional) text display element and is also an instance of StyleableTextField.
The icon display element is an instance of the BitmapImage component. BitmapImage has been augmented in the Flex 4.5 SDK to be more performant since it can cache the visual asset it is displaying. The icon element is the image that appears on the left side of the item renderer by default as shown by the figure above (see Figure 3).
The decorator element is also an instance of BitmapImage. It is often set to a chevron icon and appears on the right side of the renderer by default. It is recommended that the decorator be set to an embedded image asset for optimal performance.
The iconPlaceholder is also an instance of BitmapImage. It is the image that is displayed while the icon image is loading or if the icon image is missing. Like decorator it is recommended that the asset for iconPlaceholder be embedded for optimal performance.
When you need to customize an item renderer for a Mobile List, you have three options: extend UIComponent, extend LabelItemRender, or extend IconItemRenderer. In the Shopping Cart mobile project, check out ItemPreviewImageRenderer.as in the com.adobe.mobileshoppingcart.view.renderer package. This item renderer extends from IconItemRenderer and takes advantage of the existing display elements defined. I simply set the necessary properties and I have a smooth scrolling List.
In the Expense Tracker web project, we use the Spark DataGrid that is new in Flex 4.5 SDK. The Spark DataGrid has many improvements over the MX DataGrid. It fully supports visual customization through a rich Spark skinning contract. Additionally, the Spark DataGrid supports renderers for both the header and items, has full support for advanced column functionality like resizing and sorting and is fully accessible as well as editable. You can see the DataGrid in action by looking at DataGridView.mxml in the CRUDWeb.fxp.
The Spark DataGrid has a columns property of type IList. The columns list should contain GridColumn objects. In the Expense Tracker web application, the user has the ability to turn columns on and off via a settings controls.
In the arcitcture mentioned above, the presenter hold all the state for the views. In this case, the presenter holds the list of columns that are currently turned ‘on’ as viewable by the user. Since GridColumn falls into the category of a view object, GridColumn did not meet the critera to be put into the shared CRUDLib library project for sharing with the Expense Tracker mobile project.
To get around this I made a new interface and model object:
IGridColumnModel and GridColumnModel. IGridColumnModel is a data-only representation of a GridColumn view object. The main presenter class holds a list of GridColumnModel objects in the columnList ArrayCollection. The view, in turn, listens for changes to the columnList ArrayCollection and then uses a custom factory class to build instances of GridColumn view objects. The factory class is named GridColumnFactory and has a static method named buildGridColumn() that takes an IGridColumnModel object and returns a GridColumn. This allows all the view code to stay in the appropriate project and the state to still be held in the shared presenter code.
As with other item renderers, an eye should be kept on efficiency when creating DataGrid item renderers. Here are a few tips to creating well performing DataGrid item renderers:
Though Spark components are required for Flex Mobile projects, one exception was made and that was to allow using the MX charting components like ColumnChart, BarChart, PieChart and more. When you create a new Flex Mobile project in Flash Builder 4.5, the charting components are already included in the project’s library path so those components are immediately available in code hinting and in design view. The Sales Dashboard web and mobile projects both use the charting components to display financial information. The shared data layer as well as the shared UI charting components are contained in DashboardChartLib.fxpl. This is an example where UI code is shared between a web and mobile project via a single Flex Library project. DashboardMobile.fxp and DashboardWeb.fxp contain all of the UI code, apart from the charting components, that are specific to the web or mobile form-factor (like mobile-specific item renderers).
A common layout pattern for tablet applications is the Master/Detail layout. If you take a look at the DashboardTablet.fxp project, you will see this layout in action. When the application is in landscape mode, there is a column of small views on the left. Clicking on one of these small views opens the larger detail view on the right. When the application is in portrait mode, the left column disappears and the larger detail view fills the entire screen. The column of small master views can now be accessed via a CalloutButton in the upper left of the screen. Implementing this layout is easy SplitViewNavigator container.
Looking at DashboardTablet.mxml you will see the root mxml tag is an Application tag instead of the ViewNavigatorApplication tag seen in the other tablet projects. This is because there is not a SplitViewNavigator application type. We are still able to use elements of the ViewNavigatorApplication by using the NavigatorContent container to hold our top navigation elements. After the NavigatorContent container you will see the SplitViewNavigator container.
Inside the attributes for the SplitViewNavigator we can specify our layout for portrait and landscape states as well as whether or not we want to auto hide the first view navigator when in portrait mode. The contents of this SplitViewNavigator are two ViewNavigators. One for the master view and one for the detail view. These ViewNavigator's can have their first views assigned as well as have views pushed and popped into them like with a traditional mobile application. You can see an example of this in the goStateHandler at the top of the DashboardTablet MXML file.
In the CRUDMobile.fxp and DashboardMobile.fxp applications we created a custom MultiSelectList component that extends SkinnablePopUpContainer to create a modal full screen menu that allows a user to select an option. While this approach works great for phone devices it does not work well for tablets. With tablets, we have substantially more real estate so a full screen modal list with a handful of options is not ideal.
To solve this problem I used the new CalloutButton component in our custom MultiSelectComponent that can be found in DashboardTablet.fxp and CRUDTablet.fxp. Though its name may suggest CalloutButton is a control it is in fact a container. Whatever you put in between the begin and end tags for CalloutButton shows up in a Callout when the button is pressed.
This article barely scratches the surface of all the new features in Adobe Flash Builder 4.5 and Flex 4.5 SDK. Hopefully you got a sense of some of the things you are able to do in this new version of the framework and tool, especially around creating content for mobile smartphones and tablets. We are excited for folks to install all three of the reference applications for web and for mobile and to tease apart the code and learn best practices and tricks for writing fast and good-looking Flex code!