Wednesday, June 13, 2007

Flash for Java Programmers: Lesson 4 - ActionScript and organizing large flex code bases

Steps on learning to develop Flash, with a Java developer focus...

This is lesson 4 in my series of posts on what I learn about developing filthy rich flash apps using flex2. The other lessons are:

In this post, I will show how we extract all our ActionScript code into files sepatate from the MXML files, to get the whole thing separated a bit. I will also show how large user interfaces can be split into separate and smaller mxml files.

What is ActionScript?
It is the scripting language that you program flash frontends with. With the ActionScript version 3, it is based on the upcoming ECMAScript specification (ECMA-262) and includes language extensions for working with XML based on ECMAScript for XML (E4X, ECMA-357). It is an object oriented, dynamic language, in which you can do everything you can do with mxml, and a whole lot more, to make your applications interactive.

The Problems
When you first start programming in flex, you can simply put your ActionScript (AS) code directly inside the MXML files inside <Script>-tags. Like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
private function clickHandler() : void {
Alert.show("Hello, from embedded ActionScript");
}
]]>
</mx:Script>
<mx:Button label="Click me" click="clickHandler();"/>
</mx:Application>
But when the application logic grows more complicated, you will feel the need to extract the AS code into files separate from the xml. If nothing else, then to have xml syntax and AS syntax separated.

What more is, when the user interface of the application grows larger, it quickly becomes unfeasible to have it all in one Main.mxml file. So, we also need to split up the MXML files into separate smaller files.

The solution
What we have been using is a two-step process, where we put AS code into helper files and extract views and UI components into separate MXML files. Take this simple UI as an example, which contains a TabNavigator with two tabs:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:TabNavigator>
<mx:Panel title="Login View">
<mx:Label text="We are now in Login View"/>
</mx:Panel>
<mx:Panel title="Application Main View">
<mx:Label text="We are now in main view"/>
</mx:Panel>
</mx:TabNavigator>
</mx:Application>
In this example, the UI in each tab are very limited, but more often than not, it will be quite complex with a lot of script logic too. So, I will show how to extract the content of each tab into separate mxml files. Here are the steps:
  • Create a directory "view" at the same level as the Main.mxml file
  • Inside this directory, create LoginView.mxml and MainView.mxml
  • Move UI definition from Main.mxml into each of the files, wrapping each in a Canvas
  • Reference the new, separate view files from Main.mxml using a view namespace
Here are the contents of the LoginView.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
<mx:Panel title="Login View">
<mx:Label text="We are now in Login View"/>
</mx:Panel>
</mx:Canvas>
And here are the contents of the MainView.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
<mx:Panel title="Application Main View">
<mx:Label text="We are now in main view"/>
</mx:Panel>
</mx:Canvas>
Only thing to notice in the above two files is that the root element is a Canvas. We are not allowed to use Panel as a root element.

And last, here are the contents of the Main.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:view="view.*">
<mx:TabNavigator>
<view:LoginView />
<view:MainView />
</mx:TabNavigator>
</mx:Application>
Looking at the above code we see, that the Application element now have a namespace definition xmlns:view="view.*", which makes flex resolve elements with the view namespace into the directory named view. And the content inside the TabNavigator has been completely replaced with references to the view files, using the namespace.

And what about AS code then? How to put that inside separate files. Well, what we did was create a helper file for each mxml file. If Main.mxml had an init() function called from creationComplete, we could create a MainHelper.as file with this content:
import mx.controls.Alert;
private function init() : void {
Alert.show("init() called");
}
And then include and use it from Main.mxml like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" xmlns:view="view.*">
<mx:Script source="MainHelper.as" />
...
We actually tried calling the file Main.as, that is, the same as the mxml file, just with another extension. But this failed, in compilation, if I remember correct. My guess is, that the compiler translates the files into named types in the bytecode, where Main.mxml and Main.as then clashes. But it is a guess.

A little nice side-effect
Extracting AS code into .as files makes IDEA able to work better with them, even though it has no Flex support yet. I think it is its killer JavaScript support, that kicks in.

Still not good enough
All the organization we have done above are only for the developers to be able to manage the code base and maybe reuse some UI components. It is all still linked into one big .swf file, though. And this might become a problem when the application grows larger.

There seems to be solutions to this. I have just not had the need for it yet. If I get the need, I will blog about it here :-)

Downloading the source
I have zipped up the sources. It can be downloaded from here. Ready to be build with maven.

4 comments:

Assad said...

thanks man!

Dirk said...

I'm a Java developer just getting started with Flex. You have a real talent to explain things easily and at the same time explain important things like code organisation, instead of listing n Flex classes and methods like most tutorials do. I can only encourage you to keep going...where is lesson 6? ;-)

Tech Per said...

@Dirk:

Thanks for the nice words.

About lesson 6 - what do you want to know about? :-)

Anonymous said...

This was exactly what I was looking for since I also needed to split all my MXML code into smaller bits.

I would *really* appreciate a following tutorial on how to load additional (compiled) MXML components during runtime, too!