Home > Mobile, PureMVC > PureMVC Goes Mobile 1: MVC-driven & ready-to-compile Mobile Application with the Flex Framework! by Christian Peters

PureMVC Goes Mobile 1: MVC-driven & ready-to-compile Mobile Application with the Flex Framework! by Christian Peters

Optimizing Mobile Apps with Design Patterns

Optimizing Mobile Apps with Design Patterns

Gentle Readers: Every now and then Chandima and I have a guest post. In this case, Christian Peters who maintains a blog at http://digitale-avantgarde.com was kind enough to translate his post from German into English. (For those of you who would prefer the original German version, visit Chris’ site.) Because of the size of the post, we’ve had to divide it into two separate posts. The second half of the post will be available next week. We and Chris would appreciate your comments. Click the download button to get the entire code:
kilroy

PureMVC Goes Mobile

Let’s build a cross-platform compatible, MVC-driven & ready-to-compile Mobile Application with the Flex Framework!
A year ago, finding people who bet serious money on Flash missing a connection to the mobile world was an easy task. This is no longer the case nowadays. Adobe has introduced an iOS Compiler and AIR for Android & Blackberry Playbook. With the latest release of Flex SDK 4.5.1, the average Flash-Coder is transformed to a crossplatform-ready mobile developer. Amazing times. Let’s look at how to adjust the Standard Port of the famous PureMVC Framework to be mobile-ready! The Flex SDK ships with an integrated Navigation for Mobile Views, the ViewNavigator. There is an excellent introduction to the topic, that can be found here, but I’ll give a brief overview about the concept:

Mobile Applications – especially on Smartphones – are restricted in a very important feature: Space. If you adapt a Web app to mobile, you’ll typically have much more views because you have to present the same content on smaller displays. Flex comes to the rescue by introducing the ViewNavigator. The ViewNavigator is a container, that holds references to the available views and makes navigation between them easy. You can imagine it as an array – where the view at the zero index is visible & active. It’s not a coincidence that the ViewNavigator has array-esque methods like popView() or pushView()!

The ViewNavigator is a nice way to handle views, because it’s an easy way to navigate through an app: Every view holds a reference to the ViewNavigtor – the navigator property – and can forward the application to another view on demand.
Well, it’s not all roses with the ViewNavigator! A view has its own control-mechanism as property – while it should be vice versa. Another downside: The registering and instantiation of views are becoming tasks of Flex, while you normally want to handle those tasks in your infrastructure framework of choice! Mine is PureMVC. I want to show you a way to hook PureMVC to the registering process of the ViewNavigator to build nicely decoupled applications for the mobile world. Some experience with PureMVC is recommended, but I’ll give you a quick …

Crash Course in PureMVC

You might have guessed, that PureMVC is a reference implementation of the MVC-Design Pattern. By my personal definition, MVC is not a design pattern but a composition of design patterns. And, again by my personal definition, PureMVC is a perfect composition. Take a look at the conceptual diagram! (Also, take a look at Chandima’s work on PureMVC on this blog. Minimalist PureMVC and Move the Cheese )

PureMVC is build around four singletons, known as the Core Actors. Three of them are predictably named: Model, View and Controller. I’ll come to them in a moment. The fourth is the Facade, a design pattern meant to hide complexity from the client. The client may be a Flex Application or the Document Class of an Actionscript Project, respectively the Stage (it may be much more, because PureMVC is ported for many languages)! The client forwards a reference to itself to the Facade, and the Facade boots the framework. Thus, if views are instantiated later, the Facade forwards it to the client.

The participants of the model are named proxies, but they are not following the exact definition of the Proxy pattern. There task is to supply data from all kind of sources (XML, Database …) to Value Objects. Value Objects are simple classes without methods. They host the supplied data as public properties. All proxies are hosted in the Model-Singleton and can be retrieved from it via the Facade.
The business logic is shared among commands – stateless classes that are executing tasks. Commands are hosted in the Controller-Singleton. You are registering commands via the Facade.

The last actor – the View – hosts the Mediators. They are the interface between views and the framework. The views itself are standing outside the MVC-implementation, so they can be replaced easily. The Mediators are registering the views and listen for user actions inside of them. Then they decide how a model should be manipulated based on that action. Or they trigger a command to do it and await a notification on how to present the changed model state to the user. Since all core actors are hidden from the client, you are registering mediators like its companions: via the Facade.

Notifications are PureMVC’s own implementation of the observer pattern. Mediators can register for Notifications they care about, and Commands are registered to a notification. Models do not listen to Notifications. Notifications can be send by all participants of MVC and they can contain a generic object. Notifications are a very cool alternative to Actionscripts event system, as they are available to classes that do not implement the IEventDispatcher Interface. If you want to dive in any further, read the excellent documentation on puremvc.org! If you’re hungry to build a MVC-driven mobile app, keep reading. I’ll explain details along the way.

Finally, we’re arriving the essential topic of this article: How to adjust this composition for mobile needs?

The Bootstrap

As said above, normally the Mediators are taking care of the instanciation and registering of the views. However, in Flex Mobile Applications, the ViewNavigator claims to do it – and we have to live with it. My approach is to provide a mediator for the ViewNavigator itself and listen for events that indicate a change of the view. Then we forward this information to a command that figures out, which mediator to register.

Normally you’d give a reference to the basic view to the Facade. That way, all views that are instantiated by the mediators can be placed in the base view. Since we do not place or instantiate views in mobile navigation (the ViewNavigator does), we give a reference to the ViewNavigator to the Facade. Thus, we can build our hook to ViewNavigatorEvents later.
Fire up a new Flex Mobile Project and adjust the code like this:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1.	<?xml version="1.0" encoding="utf-8"?>
2.	<s:ViewNavigatorApplication
3.	        xmlns:fx="http://ns.adobe.com/mxml/2009"
4.	        xmlns:s="library://ns.adobe.com/flex/spark"
5.	        firstView="com.digitaleavantgarde.view.components.HomeView"
6.	        applicationDPI="240"
7.	        initialize="onInitalization(event)">
8.	        <fx:Script>
9.	                <![CDATA[
10.	                        import com.digitaleavantgarde.ApplicationFacade;
11.	                        import mx.events.FlexEvent;
12.
13.	                        private var facade:ApplicationFacade = ApplicationFacade.getInstance();
14.
15.	                        protected function onInitalization(event:FlexEvent):void
16.	                        {
17.	                                // Booting Framework
18.	                                facade.startup(this.navigator);
19.	                        }
20.	                ]]>
21.	        </fx:Script>
22.	</s:ViewNavigatorApplication>

This is just the prelude to PureMVC. Now let’s look how to use the framework! Let’s start with the Facade:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1.	package com.digitaleavantgarde
2.	{
3.	        import com.digitaleavantgarde.controller.*;
4.
5.	        import org.puremvc.as3.interfaces.IFacade;
6.	        import org.puremvc.as3.patterns.facade.Facade;
7.	        import org.puremvc.as3.patterns.observer.Notification;
8.
9.	        import spark.components.ViewNavigator;
10.
11.	        public class ApplicationFacade extends Facade implements IFacade
12.	        {
13.	                public static const NAME:String = ‘ApplicationFacade’;
14.	                public static const STARTUP:String = NAME + ‘Startup’;
15.	                public static const MEDIATE_VIEW:String = NAME + ‘MediateView’;
16.
17.	                /**
18.	                 * Returns an instance of the ApplicationFacade Singleton.
19.	                 *
20.	                 * @return ApplicationFacade
21.	                 */
22.	                public static function getInstance():ApplicationFacade
23.	                {
24.	                        if (instance == null) instance = new ApplicationFacade( );
25.	                        return instance as ApplicationFacade;
26.	                }
27.
28.	                /**
29.	                 * Register controllers.
30.	                 */
31.	                override protected function initializeController():void
32.	                {
33.	                        super.initializeController();
34.	                        registerCommand(STARTUP, StartupCommand);
35.	                        registerCommand(MEDIATE_VIEW, MediateViewCommand);
36.	                }
37.
38.	                /**
39.	                 * Fired by the viewComponent on startup.
40.	                 */
41.	                public function startup(viewNavigator:ViewNavigator):void
42.	                {
43.	                        sendNotification(STARTUP,  viewNavigator);
44.	                }
45.	        }
46.	}

What’s happening here? I’m implementing some necessary stuff and am following some best practices of building a PureMVC application. In sequence … As said, the Facade is a singleton. Thus, I’m implementing a getter to the instance in the getInstance()-Method. It’s returning a reference from the heap or is instantiating one, if none is already instantiated.
Before that, I’ve defined a static constant NAME. This is good practice, to avoid naming conflicts. You should do this in every – again EVERY – member of your PureMVC Application. This is essentially in proxies and mediators, as they can be retrieved from the Facade by name.

I also defined to other static constants, STARTUP and MEDIATE_VIEW. They will be associated with the Observer-System of PureMVC, the Notifications. If you want to broadcast a Notification along your application, you’ll do this by name. You can see this in action in the method startup(), which we called in our ViewNavigtorApplication! The method startup() does broadcast a notification, using the sendNotification() Method, that is implemented by the Facade, the proxies, the commands & the mediators!

It takes three parameters: The name of the notification (equal to the name of an event in Actionscripts event system) and a generic object (in our case a reference to the view navigator). You might add a third parameter, the type as String. This is normally obsolete, as the receiver of the notification should know how to cast the object.

Notifications can be caught by mediators and commands. The STARTUP Notification is associated with the StartupCommand: I’ve overridden the initializeController() Method to register some commands. I usually register all my commands here. In bigger projects, you might consider to register them on demand.
I’ve registered a command which class is named StartupCommand, that is instantiated when the Notification STARTUP is broadcasted, and a command which class is named MediateView. This will be triggered later, when the view changes.
To summarize: I have given access to the Facade via a getInstance() method, I have defined a name and some constants that are used as name for Notifications and I’ve registered two Commands. One of them is executed on startup.
The StartupCommands kicks in after the framework is booted. Its job is to start you application:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1.	package com.digitaleavantgarde.controller
2.	{
3.
4.	        import com.digitaleavantgarde.view.ViewNavigatorMediator;
5.
6.	        import org.puremvc.as3.interfaces.ICommand;
7.	        import org.puremvc.as3.interfaces.INotification;
8.	        import org.puremvc.as3.patterns.command.SimpleCommand;
9.
10.	        import spark.components.ViewNavigator;
11.
12.	        /**
13.	         * Registers the ViewNavigationMediator,
14.	         */
15.	        public class StartupCommand extends SimpleCommand implements ICommand
16.	        {
17.
18.	                public static const NAME:String = ‘StartupCommand’;
19.
20.	                override public function execute(notification:INotification):void
21.	                {
22.	                    facade.registerMediator(new ViewNavigatorMediator(notification.getBody() as ViewNavigator));
23.	                }
24.	        }
25.	}

There are two types of commands available in PureMVC: Simple & Macro. MacroCommands are classes that are executing multiple SimpleCommands, if you want to spread business logic among multiple SimpleCommands. We’re using the SimpleCommand here, as we do not have much logic to implement.
SimpleCommands have to overwrite the execute() method, were all actions take place.
We are registering the ViewNavigatorMediator.

The ViewNavigatorMediator

Let’s take a look!

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
1.	package com.digitaleavantgarde.view
2.	{
3.	        import com.digitaleavantgarde.ApplicationFacade;
4.
5.	        import org.puremvc.as3.interfaces.IMediator;
6.	        import org.puremvc.as3.interfaces.INotification;
7.	        import org.puremvc.as3.patterns.mediator.Mediator;
8.
9.	        import spark.components.View;
10.	        import spark.components.ViewNavigator;
11.	        import spark.events.ElementExistenceEvent;
12.
13.
14.	        public class ViewNavigatorMediator extends Mediator implements IMediator
15.	        {
16.	                public static const NAME:String = ‘ViewNavigatorMediator’;
17.
18.	                private var viewNavigator:ViewNavigator;
19.	                private var activeView:View;
20.
21.	                public function ViewNavigatorMediator(viewNavigator:ViewNavigator)
22.	                {
23.	                        this.viewNavigator = viewNavigator;
24.	                        super( NAME, viewNavigator );
25.	                }
26.
27.	                override public function onRegister():void
28.	                {
29.	                        viewNavigator.addEventListener(ElementExistenceEvent.ELEMENT_ADD, switchView);
30.	                }
31.
32.	                override public function listNotificationInterests():Array {
33.	                        return [
34.
35.	                        ];
36.	                }
37.
38.	                override public function handleNotification(notification:INotification):void {
39.
40.	                        var name:String = notification.getName();
41.
42.	                        switch (name)
43.	                        {
44.	                                // ToDo
45.	                        }
46.	                }
47.
48.	                private function switchView(evt:ElementExistenceEvent):void {
49.	                        sendNotification(ApplicationFacade.MEDIATE_VIEW, evt.element as View);
50.	                }
51.	        }
52.	}

As you’ve seen in the StartupCommand, we’ve given the ViewNavigatorMediator a reference to the ViewNavigator. We forward it to the parent class, to hold it as generic object. However, to have a strictly typed ViewNavigator, we save it to a private var, too.
We then override the onRegister() method and register an EventListener for the ElementExistenceEvent.ELEMENT_ADD-Event on the ViewNavigator (previously, the event was named ViewNavigatorEvent.VIEW_ADD but was changed).
This Event is dispatched every time when the view changes. This gives us the chance to register the appropriate mediator.
Note that we do not register the mediator here, because it’s business logic. We just take the view-property of the event – a reference to the new active view – and broadcast it along with a MEDIATE_VIEW notification. Please remember, that we have registered the MediateViewCommand for this notification in our Facade. Thus, everytime the view changes, the Command gets triggered and the new active view gets injected in it. That’s our hook!

Before we go on, let’s briefly discuss the listNotificationInterests() and handleNotifications() methods. Similar to registering commands to a specific Notification, you can register Mediators to them: Just return an array with the name of the notification, that the mediator cares about in listNotficationInterests()! The handleNotfications() method will be triggered, when that Notification is broadcast. You can then choose the appropriate action with the getName() method of the Notification and a simple switch/case construct. This is mainly associated with proxies, which are not focus of this article. Read the appendix for an example!

(Part II of this Post will be Available Next Week.)

Share

Related posts:

  1. Minimalist MVC example using the PureMVC Framework
  2. Move the Cheese: A non-Flex Actionscript example of a PureMVC Multicore Application
  3. Is MVC Obsolete? Flex, ActionScript 3.0 and the MVC Design Pattern
Categories: Mobile, PureMVC
  1. chp
    June 28, 2011 at 4:48 am | #1

    One link got lost, the detailed introduction to the viewNavigtor.

    It can be found here:

    http://corlan.org/2011/01/12/understanding-flex-mobile-views-and-viewnavigator/

  2. June 28, 2011 at 6:09 am | #2

    Thanks Chris,

    It’s embedded in the post now.

    Kindest regards,
    Bill

  3. Mario Knezovic
    July 24, 2011 at 5:43 am | #3

    Great post! I’d like to point out one subtle difference to usual PureMVC practice, something I stumbled across when I implemented a very similar approach: The reason for boostrapping PureMVC in the initialize event instead of the creationComplete event with these mobile components is that otherwise you’ll miss the add event in your ViewNavigator for the first view. Since you didn’t mention it, it’s probably immediately obvious to everybody – except me ;-)

    And btw: From my perspective the original German blog post misses the extremely interesting MediateViewCommand and how you handle identification of the views. Actually this was the most interesting part of the post for me, to compare it with my first (naive) approach: if (view is MyView)… else…

    Thank you for sharing your knowledge!

  4. chp
    July 25, 2011 at 1:53 am | #4

    Thanks for your response, Mario & pointing out the initalize() Part.

  5. cole
    July 25, 2011 at 8:27 pm | #5

    all your code samples have numbers in them. makes it hard to copy and paste. or i am missing something.

    great tutorial. looking forward to more.

  6. cole
    July 25, 2011 at 10:23 pm | #6

    sorry did not see download btn. u rule!
    my bad.
    cp

  7. Fayaz
    March 22, 2012 at 12:20 pm | #7

    I dont see the code for MediateViewCommand class. Could you please provide code for this class.

  1. No trackbacks yet.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>