One last tweek

Have made some more small changes after a discussion with Chris Hall. The main one being the creation of two puremvc actors.

1) DataLoaderProxy.
2) AssetLoaderMediator.

these wrap their own unique instance of the UnifiedLoader class, allowing users to separated their view elements (ie swf, png, jpgs etc) from their data elements (xml, JSON etc).

I have made no attempt to enforce this split, the actors are for all intents and purposes the same, so those who wish to bung all externally loaded items into either one are free to do so.

I am at the moment working on a tutorial for both day to day use of the UnifiedLoader, and one for creating custom clients for new and interesting asset/data types.

pureMVC assetLoader utility (4)

Changes
I have done some more twiddling. Mainly I realised that I needed a finer grained status than isLoaded, so I removed it and substituted a status property, whose values are enumerated in org.puremvc.as3.utilities.assetLoader.etypes.AssetInfoStatus:

  • LOADED_COMPLETE: the asset has loaded and is ready for retrieval
  • QUEUED: the asset is queued, but yet to start loading
  • LOADING: the asset is currently loading
  • ERROR: the asset failed to load, details will have been sent via the LoaderErrorEvent
  • READY: the asset has been called through the getAsset() method, has not previously been loaded and is ready to be added to the queue
  • NON_EXISTENT: the asset does not yet exist
  • I have also fixed a hole in the getAsset method logic, where it was only looking in the assetMap, not the loadQueue, or the currently loading item.
    [kml_flashembed movie=”http://www.revisual.co.uk/swf/assetloader_v3.swf” height=”500″ width=”470″ /]
    To retrieve an asset:

    // create assetInfo
    var assetInfo:IAssetInfo;
    assetInfo= assetLoader.getAsset("filePath/myImage.jpg");
    // test to see if it has already been loaded and stored
    if(assetInfo.status != AssetInfoStatus.READY)
    {
        trace("this asset has already been loaded");
        // retrieve and type asset;
        var myBMP:Bitmap = Bitmap( assetInfo.getAsset() );
    }
    else
    {
        // add the id of the client that should 
        // handle the loading of the asset
        assetInfo.clientType = ClientTypes.LOADER_CLIENT;
        // add a LoaderContext or SoundLoaderContext if needed
        assetInfo.context = new LoaderContext();
        // add any listeners required
        assetInfo.addEventListener(Event.COMPLETE, 
                                   completeHandler);
        // add the assetInfo to the load que
        assetLoader.addToQue(assetInfo);
    }

    pureMVC assetLoader utility (3)

    the main actors

    the Loader Class:
    this delegates loading tasks to its clients, and stores (if asked) the results.

    the IAssetInfo Interface:
    this is basically a value object that is requested from the Loader, on which properties or listeners may be set, and then passed back to the Loader to initiate loading.

    the Clients:
    these actually do the job of wrapping the different types of loading Objects (URLLoader, Loader, ModuleManager, Sound, NetStream… etc).

    (if you are familiar with the Flex ModuleManager, the above implimentation is very similar).

    the code
    the refactored code can be downloaded from the googlecode svn here, or viewed by clicking the souce button on the demo below.

    The loader is no means completed, but I feel that this is a good backbone to build on. It also needs some good thorough testing, but I’m confident that its basic functionality is sound.

    [kml_flashembed movie=”http://www.revisual.co.uk/swf/assetloader_v2.swf” height=”500″ width=”470″ /]

    To create and register the AssetLoaderProxy:

    // create the LoaderProxy instance
    var loaderProxy:LoaderProxy;
    loaderProxy= new LoaderProxy();
    // register the client that wraps 
    // the flash.net.URLLoader Class
    loaderProxy.registerClient(ClientTypes.URLLOADER_CLIENT, 
                               URLLoaderClient);
    // register the client that wraps 
    //the flash.display.Loader Class
    loaderProxy.registerClient(ClientTypes.LOADER_CLIENT, 
                               LoaderClient);
    // register proxy with the pureMVC framework
    facade.registerProxy(assetLoader);

    To retrieve an asset:

    // create assetInfo
    var assetInfo:IAssetInfo;
    assetInfo= assetLoader.getAsset("filePath/myImage.jpg");
    // test to see if it has already been loaded and stored
    if(assetInfo.hasLoaded)
    {
        trace("this asset has already been loaded");
        // retrieve and type asset;
        var myBMP:Bitmap = Bitmap( assetInfo.getAsset() );
    }
    else
    {
        // add the id of the client that should 
        // handle the loading of the asset
        assetInfo.clientType = ClientTypes.LOADER_CLIENT;
        // add a LoaderContext or SoundLoaderContext if needed
        assetInfo.context = new LoaderContext();
        // add any listeners required
        assetInfo.addEventListener(Event.COMPLETE, 
                                   completeHandler);
        // add the assetInfo to the load que
        assetLoader.addToQue(assetInfo);
    }

    The LoaderProxy that wraps the Loader class traps the Loader’s events and relays them as notifications to the pureMVC framework (see the enumerated type class LoaderNotificationNames).

    refactoring

    Spent last night refactoring the AssetLoader. It looks a lot better stripped down. I have also removed the typed getter methods from the IAssetContainer. You know the fileType, you know the clientLoaderType, so it can be typed after a call to the getAsset():* method. The only asset type this really affects is XML. Basically, you can’t store XML in the AssetLoader, it can only be stored in its serialised state (ie a String). This means that once it is loaded it must be retrieved, parsed, and injected into its very own model for storage and access. But that’s only good practise – no??

    The reason I’m not parsing XML within the AssetLoader is because you might want to set some of the static XML parsing properties first. This is one of the main reasons that I stopped using BulkLoader.

    I have added a few smaller interfaces:

    ICreate
    which is basically a factory method that wraps a Module or SWF asset. The create(id:String=””) method can be called on them, allowing access to classes embedded in the assets.

    IDeconstruct
    this enforces the good practice of disposing of assets properly. An IDeconstructor that knows how to handle a specific asset’s deconstruction wraps the asset and is passed into the ILoadInfo at the completion of a successful load. So a NetStream or a Bitmap can be handled in their own unique ways.

    thoughts of complexity

    After the weekly FlashBrighton geekmeet about OOP and the reduction of complexity (taken by Flexible Factory) I’m undergoing a garbage collection phase with my thoughts. I’ve decided that the automatic assignment of the correct loader client from the fileType is adding too much complexity, and I promised my self I wasn’t going to do this.

    Also, I was implementing a test for my Flex Module loader client, when I realised that it was a specialised swf. The automatic assignment just wouldn’t work in this case, so I had to create a property on the IAssetContainer that explicity set the clientLoaderType.

    If its annoying once and results in code fiddling, it’ll be even more annoying the next time etc… Any logic that assigns the correct clientLoaderType from the fileType can be implemented for a specific project.

    Also for the Notifications, I’m sending the AssetLoaderProxy itself, which is resulting in lots of getters and setters that don’t need to be there. Create a custom event object and send that as the body. This will work well with some good advice from Pedr Browne, and that is to remove my AssetLoader from the Proxy, and have a Proxy wrap it. This means that it can work in isolation from the pureMVC framework, and dispatch errors that the Proxy can handle and pass on as Notifications.

    pureMVC assetLoader utility (2)

    Been thinking a lot about the architecture of this. Currently the AssetLoaderProxy’s clients (ie the classes that actually do the loading of the different types of data) are Commands that are triggered by Notifications given by the AssetLoaderProxy. But I think this is a case “its pureMVC, let’s use Notifications”. The same effect could be achieved by an abstract client class and a client factory, without the overhead of sending a Notification, and it would make adding new clients far easier.

    I’ve also created a client for loading Flex Modules, and added functionality to extract class instances from loaded SWFs.

    I’m aiming for the end of July for my first alpha release of the AssetLoaderProxy and the LogProxy :-/ Hopefully I will have time, as it can be combined with my next job, which is a multimedia presentation tool to be implemented in pureMVC Flex and Air – YEY!

    mmm… I guess I need to look at a FileStream client too. Best put that on the list.

    Update
    Thinking some more, lets do away with a factory altogether. We can register the clients directly, they can be added and removed at run time.