Archive for the ‘ActionScript’ Category

Flash Lite Quick Tips

Saturday, November 22nd, 2008

Memory Management:

  • Read “Memory Management and Optimizations in Flash Lite” at http://www.adobe.com/devnet/devices/articles/memory_management.html
  • Watch the memory usage in the Emulator’s Memory window.  If you are unfamiliar with memory management and fragmentation, read page 6 in the link above.
  • Set no longer needed local vars to null.
  • Delete class references when you are done with them.
  • Use MovieClipLoader, loadClip, loadMovie and loadMovieNum so that you can use unloadMovie and unloadMovieNum to free memory as much as possible.
  • Divide your app into multiple swfs to distribute the load.  This is the key to distributing load in a large mobile application.
  • Remember that MovieClips exported using Linkage in the Library add additional weight that cannot be removed.  If you have a lot of Linkage, distribute into multiple SWFs.
  • Keep tweens to a minimum.  One at a time, if possible.
  • Do not tween alpha or apply any scaling, if possible.

Testing:

  • Test on the actual device ASAP.
  • When working in the Device Manager’s Emulator choose the actual device from the Emulators Online Library.  The Sample Device Set’s tend to have significantly more memory and all features enabled, and therefore do not give you an accurate idea of how your app will perform on the actual device.
  • Review the Device Profile for the selected device, particularly to determine what Content Types are available and what FSCOMMAND2 commands are available for each content type.

What to do when:

  • If you get a “Internet: Unable to connect to network. Try again later.” message while running your app on the phone, this is likely caused by a load process unable to complete.  For example, if you are dynamically loading a series of images into a SWF or a MovieClip, and the destination for those images is removed before they complete their load, you will receive the above error message for each image that was unable to load.  To resolve this you will either need to wait for images/data to finish loading, stop the images/data from continuing to load, or both before continuing with your event.
  • If something works in the emulator but not on the actual device, test on a different device (a different make and model).  This will help determine the scope of the problem.
  • If you are dynamically loading images and you find that they display as expected in the emulator, but not on the phone, you may need to embed each image into a swf.

Emulator Bug:

  • Not all device content types support full screen.  If you have been testing on a device content type that does, and then switch to one that does not, it may still display in full screen mode, despite the fact that it actually does not support full screen.  If you continue to choose other content types and then return it will usually return to non-full screen if not supported.  Check the Device Profile FSCOMMAND2 list for accurate specs on the phone.

Tips for building your app:

  • Create a KeyManager class that you can pass a class reference to, so that the KeyManager can access the interface definitions of that reference.  The KeyManager class will handle the onKeyDown events for the soft keys, d-pad, number keys, and any additional keys you may have.
  • If you are running a main swf locally and there are other sfws that live on a server and need access to your local swf, you will need to set allow the network swfs access.  Add System.security.allowDomain( “http:www.somedomain.com” ); to the local swf.
  • You do not need to set the fscommand2 setSoftKeys command when running your app in the emulator, but you do when running it on the actual device if you want control of the soft keys.
  • Consider running an event that calls the fscommand2 extendBackLight command to keep your app lit.  For example, set an interval that runs every 15 seconds to extend the back light duration.

JavaScript in ActionScript 3

Saturday, August 30th, 2008

There is a new way to communicate with JavaScript from ActionScript.  In AS2 you could do things like close a window like so:

on (release)
    getURL("javascript:window.close()");
}
So in AS3 you might expect this to convert to something like:
private function onMouseClick( event:MouseEvent ):void {
    navigateToURL( new URLRequest( "javascript:closeWindow()" ) );
}
But no. I tried this many times, in many different forms before I finally found the new method for communicating with JavaScript in AS3.
private function onMouseClick( event:MouseEvent ):void {
    ExternalInterface.call('window.close');
}
With the ExternalInterface class in ActionScript you can do the following on the HTML page:

  • Call any JavaScript function.
  • Pass any number of arguments, with any names.
  • Pass various data types (Boolean, Number, String, and so on).
  • Receive a return value from the JavaScript function.

From JavaScript on the HTML page, you can:

  • Call an ActionScript function.
  • Pass arguments using standard function call notation.
  • Return a value to the JavaScript function.
Unfortunately though, Adobe AIR currently does not support the ExternalInterface class. Learn more about the ExternalInterface API at Adobe’s live docs.

SharedObject a.k.a. Flash Cookies

Thursday, August 28th, 2008

Per the ActionScript API:

The SharedObject class is used to read and store limited amounts of data on a user’s computer or on a server. Shared objects offer real-time data sharing between multiple client SWF files and objects that are persistent on the local computer or remote server. Local shared objects are similar to browser cookies and remote shared objects are similar to real-time data transfer devices. To use remote shared objects, you need Adobe Flash Media Server.

I find this to be very useful and so I have put together a simple class that will allow you to save, retrieve, and clear values from your SharedObject.

package {
    import flash.events.NetStatusEvent;
    import flash.net.SharedObject;
    import flash.net.SharedObjectFlushStatus;

    public class LocalSharedObject {

        // private properties
        private var _sharedObject:SharedObject;

        /*********************************************
         *
         *         PUBLIC METHODS
         *
         * *******************************************/     

        public function LocalSharedObject(name:String,
                                          localPath:String = null,
                                          secure:Boolean = false) {

            _sharedObject = SharedObject.getLocal(name, localPath, secure);

        }

        public function setValue( name:String, value:Boolean ):void {
            _sharedObject.data[name] = value;

            var flushStatus:String = null;
            try {
                flushStatus = _sharedObject.flush(10000);
            } catch (error:Error) {
                trace("Error...Could not write SharedObject to disk\n");
            }
            if (flushStatus != null) {
                switch (flushStatus) {
                    case SharedObjectFlushStatus.PENDING:
                        trace("Requesting permission to save object...\n");
                        _sharedObject.addEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
                        break;
                    case SharedObjectFlushStatus.FLUSHED:
                        trace("Value flushed to disk.\n");
                        break;
                }
            }
            trace("\n");
        }

        public function getValue( name:String ):Boolean {
            return _sharedObject.data[name];
        }

        public function clearValue( name:String ):void {
            trace("Cleared saved value for "+name+");
            trace("Reload SWF and the value should be \"undefined\".\n\n");
            delete _sharedObject.data[name];
        }

        public function clearAllValues():void {
            trace("Cleared all saved value);
            trace("Reload SWF and the value should be \"undefined\".\n\n");
            _sharedObject.clear();
        }

        /*********************************************
         *
         *         PRIVATE METHODS
         *
         * *******************************************/

        private function onFlushStatus(event:NetStatusEvent):void {
            trace("User closed permission dialog...\n");
            switch (event.info.code) {
                case "SharedObject.Flush.Success":
                    trace("User granted permission -- value saved.\n");
                    break;
                case "SharedObject.Flush.Failed":
                    trace("User denied permission -- value not saved.\n");
                    break;
            }
            trace("\n");

            _sharedObject.removeEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
        }

    }
}

Now you’re pretty much done.  From another actionscript class, flex component, or whatever, just add something like the following:

import LocalSharedObject;

private var _myApplicationName:String = "My Application Name";
private var _myLocalPath:String = "/";
private var _lso:LocalSharedObject = new LocalSharedObject(_myApplicationName, _myLocalPath);

private function myFunction():void {
    trace(_lso.getValue( "newLSOname" ));  // returns false if value has not been set
    _lso.setValue( "newLSOname", true );  // sets value to true
    trace(_lso.getValue( "newLSOname" ));  // returns true
}

Note: Setting myLocalPath equal to “/” (slash) makes the shared object available to all SWF files in the domain, but increases the likelihood of name conflicts with other shared objects in the domain.

I’ll post a working example to play with soon.