Archive for the 'ActionScript 3' Category

Embedding assets with ResourceBundle

Monday, August 4th, 2008

Here’s a quick tip you won’t find easily on live docs…

Yesterday I found myself needing to embed assets in a .properties file (ResourceBundle) however after looking through the Flex documentation I wasn’t completely satisfied with the examples that were available. So I tried something pretty simple and it works perfectly.

To embed an external asset such as an image, audio file, font etc you need only specify an embed directive just as one normally would for an asset, and the file will be embedded in the application. This approach is very much like using the embed directive to embed assets in CSS but only with properties files instead.

For example, suppose you wanted to embed an image named, “image.jpg” using a properties file. To do so simply define the image as follows:

IMAGE = Embed(source="image.jpg")

Then to display the embedded image simply reference the class object to which it has been embedded as follows:

ResourceManager.getInstance().getClass("images", "IMAGE");

And that’s it. Same applies for all embedded assets. I also provided a quick example as well - complete with my son Anthony on the Piano!.

XMLAsset: API for embedded XML files

Sunday, July 27th, 2008

Back in February I blogged about how to embed arbitrary file types in ActionScript (see “Embedding assets with application/octet-stream” for the complete post). That post was inspired by some work I was doing at the time which involved embedding XML files in ActionScript as an alternative to using the <mx:Model> tag in mxml. In the time since I have created a simple yet useful class which can be utilized as both a utility a concrete or a base class to facilitate decoding an embedded XML file to an XML object.

XMLAsset provides an API which allows for the decoding of an embedded XML file (via the [Embed] metadata tag / compiler directive) to a native XML object. There are three different ways XMLAsset can be implemented, the first of which is to simply create an instance of XMLAsset and pass the constructor a reference to an embedded XML asset as follows:

import com.ericfeminella.xml.XMLAsset;

[Embed("config.xml")]
private static const Asset:Class;

var config:XMLAsset = new XMLAsset( Asset );
trace( config.xml.toString() );
 

In the above example we are simply creating an instance of XMLAsset and passing a reference to an embedded XML asset from which to decode to a native XML object. From there we can access the decoded xml object as needed.

The second implementation is to sub-class XMLAsset and pass in a reference to a specific embedded xml file by calling super on XMLAsset, as can be seen in the following:

package
{
    import com.ericfeminella.xml.XMLAsset;

    public class Config extends XMLAsset
    {
        [Embed("config.xml")]
        private static const Asset:Class;
       
        public function Config()
        {
            super( Asset );
        }
    }
}

// client imlementation:
var config:Config = new Config();
trace( config.xml.toString() );
 

In the above example we are simply extending XMLAsset and passing a reference of the embedded asset to super. From there we can access the decoded xml object as needed.

The third way to utilize XMLAsset is to invoke the static createXML method directly. To do so we pass in an embedded XML asset just as we did in the first to examples. The createXML method returns a native XML object. An example is as follows:

// client imlementation:
[Embed("config.xml")]
private static const Asset:Class;

var config:XML = XMLAsset.createXML( Asset );
trace( config.toString() );
 

One thing to keep in mind is if the file which is to be embedded contains XML but does not have the recognized .xml extension the compiler will throw an error. In such cases you need only specify the mimeType as “application/octet-stream” in order to embed the file without error, however I suggest always using the .xml extension whenever possible as in the event the file should contain invalid XML mark-up you will get an error during compilation rather than at runtime. In any case embedding an XML file with an extension other than .xml is very simple, an example of which can be seen in the following:

// client imlementation:
[Embed("app.config", mimeType="application/octet-stream")]
private static const asset:Class;

var config:XML= XMLAsset.createXML( asset );
trace( config.toString() );
 

And that’s all there is to it. Enjoy.

AIR Cairngorm 2.0

Sunday, June 22nd, 2008

I have received quite a few emails since the release of AIR 1.0 and Flex 3.0 regarding the AIR Cairngorm API which I developed last year. In the time since I have been working primarily with a modified version of AIR Cairngorm which I used on a number of successful real world AIR applications, however I simply have not had the time to document and refactor for general use until recently.

In case you are not familiar with AIR Cairngorm it is an open source project built on top of Adobe Cairngorm which provides a framework for working with the Adobe AIR SQLite API while building an application with Cairngorm.

AIR Cairngorm is built around the SQLService class which essentially wraps the AIR SQL APIs to provide a uniform interface which can be utilized as a service, much in the same way one would work with RPC services in a typical Cairngorm application. SQLService provides an API for both synchronous and asynchronous implementations.

In the time since the initial development and release of AIR Cairngorm, which was during the early alpha releases of AIR, there has been many changes to the SQL APIs in AIR. In addition I have also developed some new best practices for working with Adobe AIR and Cairngorm, all of which I tried to roll into this latest release where possible.

The following is a brief description of the current AIR Cairngorm API:

AIRServiceLocator: The AIRServiceLocator is a sub class of Cairngorm ServiceLocator, therefore it inherits the same API as ServiceLocator while also adding additional support for working with local databases via the getSQLService and hasSQLService methods.
AIRServiceLocator

SQLService: The SQLService class essentially wraps the SQLStatement and SQLConnection classes. SQLService allows developers to create an mxml implementation defined on a Cairngorm ServiceLocator just as one would with typical RPC services (e.g. HTTPServices, WebService etc.)
SQLService

ISQLResponder: ISQLResponder provides a consistent API from which asynchronous SQLStatement execution results and faults can be handled. ISQLResponder is very similar to IResponder in that it defines both a result and fault handler however with a slightly different signature which is specific to a SQLStatement result / fault, (i.e. strongly typed parameters).
ISQLResponder

SQLStatementHelper: SQLStatementHelper is an all static utility class which facilitates substituting tokens in a SQL statement with arbitrary values.
SQLStatementHelper

I have also created a custom version of my Cairngen project specifically targeting AIR Cairngorm code generation. In addition I will be making some future updates to AIR Cairngorm which will include support for various other AIR APIs in Cairngorm, so stay tuned.

Below I have provided downloads to the source, binary, air.cairngen and asdocs as well as asynchronous and synchronous example projects:
source
binary
examples
asdoc
air cairngen
air cairngorm (all)

Implementing interfaces in mxml

Monday, May 19th, 2008

Most Flex developers are aware that mxml files are essentially declarative representations of ActionScript classes, that is, during compilation the mxmlc compiler generates ActionScript 3.0 classes from mxml files before being converted into bytecode that runs in Flash Player. This can be seen by setting the compiler argument -keep-generated-actionscript to true.

You may be thinking “yeah I know this, and…”, however in the past week I have had two talented Flex developers say to me: “but you can’t implement interfaces in mxml… Can you?”

Now if you think about that statement a bit more you will probably realize that you most certainly can, however it mat not seem so obvious at first as developers tend to think of mxml for what it is, a markup language and not necessarily from a compilation perspective.

So in case you are not aware how interfaces can be implemented in mxml I have provided a few simple examples below which demonstrate how a custom component can implement an interface, in this case mx.rpc.IResponder.

First you define the interface that the component will implement using the implements property of the component.

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
         implements="mx.rpc.IResponder" >
</mx:VBox>

Next you simply implement the operations defined by the interface as you normally would in a class:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
         implements="mx.rpc.IResponder" >
    <mx:Script>
        <![CDATA[

            public function result(data:Object) : void
            {
                // implementation
            }
           
            public function fault(info:Object) : void
            {
                // implementation
            }
        ]]>
    </mx:Script>
</mx:VBox>

Now you may be wondering how multiple interfaces are implemented in mxml? This is very easy as well, simply specify the fully qualified class path of each interface as a CSV (Comma-separated values). An example can be seen in the following:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
          implements="mx.rpc.IResponder,mx.core.IUID" >
    <mx:Script>
        <![CDATA[
                public function result(data:Object) : void
                {
                     // implementation…
                }

                public function fault(info:Object) : void
                {
                     // implementation…
                }

                public function get uid() : String
                {
                     // implementation…
                }

                public function set uid(value:String) : void
                {
                     // implementation…
                }
        ]]>
    </mx:Script>
</mx:VBox>

And that’s all there is to it.