Monday, November 29, 2010

Battle For MVC in Flex 4 : Refences between mxml files

I've been trying to build my new game in Flash. In part because I hoped I would be able to prototype it faster, and a it part to learn a new framework. From day one I've kept a strict design principle in place, keep the MVC seperation of concerns while using the default framework. That is, I'm not going to learn and rely on a third party framework to handle dependency injection, MVC, or whatever else.

My primary focus is keeping business logic out the view file. This ideology seems to fly in the face of what adobe preaches from their example pages and forum comments. Designers aside, I think it's a little foolish to ignore the lessons that the Java world learned while it evolved from raw jsps to frameworks like Spring MVC. I believe seperation of concerns makes code exponentially more maintainable and readable.

I consider the mxml files to be the 'view', and I provide a home-spun 'controller' Actionscript class per view.

You can and must define non-visual elements like the controller in mxml files in order to hook into the flex framework. This necessity separates Flex application from Air applications as far as I can tell. Flex is web based, Air is not. So Air is was of the question for this project.

So I now have a view file, that I need to declare my controllers in. I also need to pass references of the view elements to the controller, all in the same file. It ends up being that the mxml file is not only my view but also my dependency injection configuration. In JavaEE terms, the mxml file became my spring config file and my jsp.

My project is still small, but so far this approach has worked great!

Over the long thanksgiving weekend however, I had a bit of scare. I thought I finally reached the point where my fever dream MVC house of cards whas about to crumble. I needed to give one controller a reference to another, defined in a seperate mxml file. This was my first attempt :


...

< fx:Declarations>

< controllers:MainMenuController id="controller" gameViewController="{gameview.gameViewController}" />

< /fx:Declarations>

< views:Gameview id="gameview" includeIn="State2"/>

...


"Gameview" is a Group Element defined in a different mxml file.

The "gameviewViewController" is a variable defined in the declarations block of "Gameview".

The result of this code was a null pointer exception. I was slightly perplexed. In my troubleshooting haze I resorted to global variables and custom Group definitions. Eventually it dawned on me that I didn't have a syntax issue but an instantiation issue.

The "Gameview" view is tied to "State2" of the core application file. Flex will not instantiate the objects in different states by default. The solution was to add the following flag to the "Gameview" declaration : itemCreationPolicy="immediate"


...

< fx:Declarations>

< controllers:MainMenuController id="controller" gameViewController="{gameview.gameViewController}" />

< /fx:Declarations>

< views:Gameview itemCreationPolicy="immediate" id="gameview" includeIn="State2" />

...


This caused the gameview object to be instantiated at startup and I was able to maintain my view/di behavior. This may have memory consequences down the line, but I'll cross that bridge when I get to it :).