Another custom Flex preloader but with RSL support

Actionscript, Flex Add comments

This post has a great article on building a custom Flex preloader which also allows you to handle the progress of the runtime shared libraries that the Flex framework now loads into the users cache.

The DownloadProgressBar component allows you to view the progress of the runtime shared libraries but be aware that it can only tell you about the RSL as it loads and as there may be more than one it is practically impossible to get any indication of how many bytes in total the app is going to load. For this reason you may have seen erratic preloaders out there at the moment using all kinds of colourful language to tell you what it’s doing … “loading assets”, “modules”, “opening the champagne” etc. This is all done to keep the user occupied while each of the elements are loaded.

Then there’s the actual SWF file. Thankfully there are separate events to handle this so if you prefer you can still display the progress of the main SWF and then when it is completed change your display to inform the user that you are “initialising” which shouldn’t be too long after the main SWF has finished. Indeed your dependencies may have finished before the SWF.

I guess the only way to do this accurately is to know up front exactly how many bytes your application is going to load and then as you get the information from ProgressEvent.bytesLoaded from both the SWF and the RSL you can adjust your percentage calculation accordingly. If anyone does know how you can programmatically detect this I’d love to hear it.

Thanks to Bernhard Hirschmann and Jesse Warden for the work they’ve done and purely for my own reference here’s the class …

Custom Preloader for Flex with RSL support

  1. package
  2. {
  3.     import flash.display.MovieClip;
  4.     import flash.display.Sprite;
  5.     import flash.events.Event;
  6.     import flash.events.ProgressEvent;
  7.    
  8.     import mx.events.FlexEvent;
  9.     import mx.events.RSLEvent;
  10.     import mx.preloaders.DownloadProgressBar;
  11.  
  12.     /**
  13.      * This class extends the lightweight DownloadProgressBar class.  This class
  14.      * uses an embedded Flash 8 MovieClip symbol to show preloading.
  15.      * For handling both, SWF and RSL download, it separated its download progress
  16.      * by handling the appropriate events, i.e. RSLEvent
  17.      *
  18.      * @author jessewarden
  19.      * @author Bernhard Hirschmann (http://coding.bhirschmann.de)
  20.      */   
  21.     public class Preloader extends DownloadProgressBar
  22.     {
  23.        
  24.         /**
  25.          * The Flash 8 MovieClip embedded as a Class.
  26.          */       
  27.         [Embed(source="../assets/flash/preloader.swf", symbol="Preloader")]
  28.         private var FlashPreloaderSymbol:Class;
  29.        
  30.         private var clip:MovieClip;
  31.        
  32.     private var    isRslDownloading:Boolean = false;
  33.    
  34.         private var rslPercent:Number = 0;
  35.         private var swfPercent:Number = 0;
  36.        
  37.         private var rslBytesTotal:Number;
  38.         private var rslBytesLoaded:Number = 0;
  39.        
  40.         private var swfBytesTotal:Number;
  41.         private var swfBytesLoaded:Number = 0;
  42.        
  43.         public function Preloader()
  44.         {
  45.             super();
  46.            
  47.             // instantiate the Flash MovieClip, show it, and stop it.
  48.             // Remember, AS2 is removed when you embed SWF's,
  49.             // even "stop();", so you have to call it manually if you embed.
  50.             clip = new FlashPreloaderSymbol();
  51.             addChild(clip);
  52.             clip.gotoAndStop("start");
  53.         }
  54.        
  55.        public override function set preloader(preloader:Sprite):void
  56.     {                   
  57.       trace("starting...");
  58.  
  59.       // runtime shared library
  60.       preloader.addEventListener( RSLEvent.RSL_PROGRESS, onRSLDownloadProgress );
  61.       preloader.addEventListener( RSLEvent.RSL_COMPLETE, onRSLDownloadComplete );
  62.       preloader.addEventListener( RSLEvent.RSL_ERROR, onRSLError );
  63.  
  64.       // application
  65.       preloader.addEventListener( ProgressEvent.PROGRESS, onSWFDownloadProgress );   
  66.       preloader.addEventListener( Event.COMPLETE, onSWFDownloadComplete );
  67.      
  68.       // initialization
  69.       preloader.addEventListener( FlexEvent.INIT_PROGRESS, onFlexInitProgress );
  70.       preloader.addEventListener( FlexEvent.INIT_COMPLETE, onFlexInitComplete );
  71.      
  72.       clip.preloader.rsl_amount_txt.text = clip.preloader.app_amount_txt.text = "0%";
  73.      
  74.       centerPreloader();
  75.     }
  76.        
  77.     /**
  78.      * Makes sure that the preloader is centered in the center of the app.
  79.      *
  80.      */       
  81.     private function centerPreloader():void
  82.         {
  83.             x = (stageWidth / 2) - (clip.width / 2);
  84.             y = (stageHeight / 2) - (clip.height / 2);
  85.         }
  86.        
  87.     /**
  88.      * Updates the progress bar.
  89.      */
  90.     private function updateProgress():void
  91.     {
  92.       var p:Number = Math.round( (rslPercent + swfPercent) / 2 );
  93.         clip.preloader.gotoAndStop(p);
  94.     }
  95.    
  96.         /**
  97.          * As the RSL (runime shared library) (frame 2 usually) downloads, this event gets called.
  98.          * You can use the values from this event to update your preloader.
  99.          * @param event
  100.          *
  101.          */       
  102.         private function onRSLDownloadProgress( event:ProgressEvent ):void
  103.     {
  104.         isRslDownloading = true;
  105.        
  106.         rslBytesTotal = event.bytesTotal;
  107.         rslBytesLoaded = event.bytesLoaded;
  108.         rslPercent = Math.round( (rslBytesLoaded / rslBytesTotal) * 100);
  109.         trace("onRSLDownloadProgress: rslBytesLoaded " + rslBytesLoaded);
  110.         trace("onRSLDownloadProgress: rslBytesTotal " + rslBytesTotal);
  111.         trace("onRSLDownloadProgress: " + rslPercent + "%");
  112.         clip.preloader.rsl_amount_txt.text = String(rslPercent) + "%";
  113.        
  114.         updateProgress();
  115.     }
  116.    
  117.     /**
  118.      * When the download of frame 2
  119.      * is complete, this event is called. 
  120.      * This is called before the initializing is done.
  121.      * @param event
  122.      *
  123.      */       
  124.     private function onRSLDownloadComplete( event:RSLEvent ):void
  125.     {
  126.         trace("onRSLDownloadComplete: 100% - bytes total: " + event.bytesTotal);
  127.            clip.preloader.gotoAndStop(100);
  128.         clip.preloader.rsl_amount_txt.text = "100%";
  129.         rslPercent = 100;
  130.     }
  131.  
  132.     private function onRSLError( event:RSLEvent ):void
  133.     {
  134.         trace("onRSLError: " + event.errorText + " - " + event.url);
  135.         clip.preloader.status_txt.text = event.errorText;
  136.     }
  137.  
  138.         /**
  139.          * As the SWF (frame 2 usually) downloads, this event gets called.
  140.          * You can use the values from this event to update your preloader.
  141.          * @param event
  142.          *
  143.          */       
  144.         private function onSWFDownloadProgress( event:ProgressEvent ):void
  145.     {
  146.         swfBytesTotal = event.bytesTotal;
  147.         swfBytesLoaded = event.bytesLoaded;
  148.        
  149.         if ( isRslDownloading ) {
  150.           // as soon as RSL starts downloading the SWF data are added by the RSL values
  151.           swfBytesTotal -= rslBytesTotal;
  152.           swfBytesLoaded -= rslBytesLoaded;
  153.         }
  154.         swfPercent = Math.round( (swfBytesLoaded / swfBytesTotal) * 100);
  155.         trace("onSWFDownloadProgress: " + swfPercent + "%");
  156.         trace("onSWFDownloadProgress: swfBytesLoaded " + swfBytesLoaded);
  157.         trace("onSWFDownloadProgress: swfBytesTotal " + swfBytesTotal);
  158.         clip.preloader.app_amount_txt.text = String(swfPercent) + "%";
  159.  
  160.         updateProgress();
  161.     }
  162.    
  163.     /**
  164.      * When the download of frame 2
  165.      * is complete, this event is called. 
  166.      * This is called before the initializing is done.
  167.      * @param event
  168.      *
  169.      */       
  170.     private function onSWFDownloadComplete( event:Event ):void
  171.     {
  172.         trace("onSWFDownloadComplete: 100%");
  173.            clip.preloader.gotoAndStop(100);
  174.         clip.preloader.app_amount_txt.text = "100%";
  175.         swfPercent = 100;
  176.     }
  177.    
  178.     /**
  179.      * When Flex starts initilizating your application.
  180.      * @param event
  181.      *
  182.      */       
  183.     private function onFlexInitProgress( event:FlexEvent ):void
  184.     {
  185.         //trace("onFlexInitProgress: Initializing...");
  186.         try {
  187.           clip.preloader.gotoAndStop(100);
  188.           clip.preloader.status_txt.text = "Initializing...";
  189.         }
  190.         catch (e:Error) {
  191.         }
  192.     }
  193.    
  194.     /**
  195.      * When Flex is done initializing, and ready to run your app,
  196.      * this function is called.
  197.      *
  198.      * You're supposed to dispatch a complete event when you are done.
  199.      * I chose not to do this immediately, and instead fade out the
  200.      * preloader in the MovieClip.  As soon as that is done,
  201.      * I then dispatch the event.  This gives time for the preloader
  202.      * to finish it's animation.
  203.      * @param event
  204.      *
  205.      */       
  206.     private function onFlexInitComplete( event:FlexEvent ):void
  207.     {
  208.         trace("onFlexInitComplete");
  209.         clip.addFrameScript(21, onDoneAnimating);
  210.         clip.gotoAndPlay("fade out");
  211.     }
  212.    
  213.     /**
  214.      * If the Flash MovieClip is done playing it's animation,
  215.      * I stop it and dispatch my event letting Flex know I'm done.
  216.      * @param event
  217.      *
  218.      */       
  219.     private function onDoneAnimating():void
  220.     {
  221.         trace("onDoneAnimating");
  222.         clip.stop();
  223.         dispatchEvent( new Event( Event.COMPLETE ) );
  224.     }
  225.        
  226.     }
  227. }

Digg!

2 Responses to “Another custom Flex preloader but with RSL support”

  1. Custom Preloader in FlashBuilder « The Algorithmist Says:

    [...] 3 to 4. If memory serves, the definitive modern tutorial on the topic was provided by Jesse Warden. This site contains a sample code with references to Jesse’s work.  You may, however, gain a lot of insight into how the [...]

  2. Nabil Says:

    Can, I used this preloader for a 3D.DAE model using with augmented reality?

Leave a Reply

 
WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in