Showing the download progress of an application

The application containers support an application preloader that uses a download progress bar to show the download and initialization progress of an application SWF file. By default, the application preloader is enabled. The preloader tracks how many bytes have been downloaded and continually updates the progress bar.

The download progress bar displays information about two different phases of the application: the download phase and the initialization phase. The application container’s creationComplete event dismisses the preloader.

Flex includes two download progress bar classes: the SparkDownloadProgressBar (Spark) and the DownloadProgressBar (MX). The following image shows the Spark download progress bar:

A. Spark download progress bar. B. Initialization progress track. C. Download progress track.

When the SWF file is downloading, download progress track expands. When the application is initializing, the initilization progress track expands. The SparkDownloadProgressBar class does not contain text.

The following example shows the MX download progress bar during the initialization phase:

The download progress bar during the initialization phase

The MX download progress bar supports text. The bar displays the text “Downloading app” during the SWF download. It displays the text “Initializing app” during application initialization.

The download progress bar is not displayed if the SWF file is on your local host or if it is already cached. If the SWF file is not on your local host and is not cached, the progress bar is displayed if less than half of the application is downloaded after 700 milliseconds of downloading.

Adding a splash screen

As an alternative to the preloader, you can display a splash screen instead. The splash screen appears during the time of application startup. For information on using a splash screen, see Add a splash screen to an application.

Setting the download progress bar class

By default, an Application container uses the SparkDownloadProgressBar class. To configure the Application container to use the MX class, DownloadProgressBar, use the preloader property as the following example shows:

<s:Application ... preloader="mx.preloaders.DownloadProgressBar">

Disabling the download progress bar

To disable the download progress bar, set the usePreloader property of the Application container to false, as the following example shows:

<s:Application ... usePreloader="false">

Creating a custom progress bar

To create a custom download progress bar, you can create a subclass of the SparkDownloadProgressBar or DownloadProgressBar class, or create a subclass of the flash.display.Sprite class that implements the mx.preloaders.IPreloaderDisplay interface.

You can implement a download progress bar component as a SWC component or an ActionScript component. A custom download progress bar component that extends the Sprite class should not use any of the standard Flex components because it would load too slowly to be effective. Do not implement a download progress bar as an MXML component because it also would load too slowly.

To use a custom download progress bar class, you set the preloader property of the application container to the path of a SWC component class or ActionScript component class. A SWC component must be in the same directory as the MXML file or in a directory on the classpath of your application. An ActionScript component can be in one of those directories or in a subdirectory of one of those directories. When a class is in a subdirectory, you specify the subdirectory location as the package name in the preloader value; otherwise, you specify the class name.

The code in the following example specifies a custom download progress bar called CustomBar that is located in the myComponents/mybars directory below the application’s root directory:

<s:Application ... preloader="myComponents.mybars.CustomBar">

Download progress bar events

The operation of the download progress bar is defined by a set of events. These events are dispatched by the Preloader class. The SparkDownloadProgressBar and DownloadProgressBar classes defines an event listener for all these events.

Within your custom class, you can optionally override the default behavior of the event listener. If you create a custom download progress bar as a subclass of the Sprite class, define an event listener for each of these events.

The following table describes the download progress bar events:

Event

Description

ProgressEvent.PROGRESS

Dispatched when the application SWF file is being downloaded. The first PROGRESS event signifies the beginning of the download process.

Event.COMPLETE

Dispatched when the SWF file has finished downloading. Either zero or one COMPLETE event is dispatched.

FlexEvent.INIT_COMPLETE

Dispatched when the application finishes initialization. This event is always dispatched once, and is the last event that the Preloader dispatches.

The download progress bar must dispatch a COMPLETE event after it has received an INIT_COMPLETE event. The COMPLETE event informs the Preloader that the download progress bar has completed all operations and can be dismissed.

The download progress bar can perform additional tasks, such as playing an animation, after receiving an INIT_COMPLETE event, and before dispatching the COMPLETE event. Dispatching the COMPLETE event should be the last action of the download progress bar.

FlexEvent.INIT_PROGRESS

Dispatched when the application completes an initialization phase, as defined by calls to the measure(), commitProperties(), or updateDisplayList() methods. This event describes the progress of the application in the initialization phase.

RSLEvent.RSL_ERROR

Dispatched when a Runtime Shared Library (RSL) fails to load.

RSLEvent.RSL_LOADED

Dispatched when an RSL finishes loading. The total bytes and total loaded bytes are included in the event object. This event is dispatched for every RSL that is successfully loaded.

RSLEvent.RSL_PROGRESS

Dispatched when an RSL is being downloaded. The first progress event signifies the beginning of the RSL download.

The event object for this event is of type RSLEvent.

Creating a simple download progress bar class

The easiest way to create your own download progress bar is to create a subclass of the SparkDownloadProgressBar or DownloadProgressBar class, and then modify it for your application requirements.

The following example shows a custom download progress bas based on the SparkDownloadProgressbar class. This class overrides the getter methods for the SparkDownloadProgressbar.backgroundImage and SparkDownloadProgressbar.backgroundSize properties to show an image during application download and inititialization:
package myComponents
{
    import mx.preloaders.*; 
    import flash.events.ProgressEvent;

    public class SparkDownloadProgressBarSubClassMin extends SparkDownloadProgressBar
    {
        public function SparkDownloadProgressBarSubClassMin() {   
            super();
        }
        
        // Embed the background image.     
        [Embed(source="logo.jpg")]
        [Bindable]
        public var imgCls:Class;

        // Override to set a background image.     
        override public function get backgroundImage():Object{
            return imgCls;
        }
        
        // Override to set the size of the background image to 100%.     
        override public function get backgroundSize():String{
            return "100%";
        }
        
        // Override to return true so progress bar appears
        // during initialization.       
        override protected function showDisplayForInit(elapsedTime:int, 
            count:int):Boolean {
                return true;
        }

        // Override to return true so progress bar appears during download.     
        override protected function showDisplayForDownloading(
            elapsedTime:int, event:ProgressEvent):Boolean {
                return true;
        }
    }

}
The following application uses this custom class:
<?xml version="1.0"?> 
<!-- containers\application\SparkMainDPBMin.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    preloader="myComponents.SparkDownloadProgressBarSubClassMin">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout> 
 
    <!-- Add a couple of controls that don't do anything. -->
    <s:Button label="Click Me"/>
    <s:TextInput text="This is a TextInput control."/>
</s:Application>

The executing SWF file for the previous example is shown below:

The Spark download progress bar does not support text, but the MX one does. The next example creates a subclass of the MX DownloadProgressBar class to define custom strings for the download progress bar, and set the minimum time that it appears, as the following example shows:

package myComponents
{
    import mx.preloaders.*; 
    import flash.events.ProgressEvent;

    public class DownloadProgressBarSubClassMin extends DownloadProgressBar
    {
        public function DownloadProgressBarSubClassMin()
        {   
            super();
            // Set the download label.
            downloadingLabel="Downloading app..."
            // Set the initialization label.
            initializingLabel="Initializing app..."
            // Set the minimum display time to 2 seconds.
            MINIMUM_DISPLAY_TIME=2000;
        }
        
        // Override to return true so progress bar appears
        // during initialization.       
        override protected function showDisplayForInit(elapsedTime:int, 
            count:int):Boolean {
                return true;
        }

        // Override to return true so progress bar appears during download.     
        override protected function showDisplayForDownloading(
            elapsedTime:int, event:ProgressEvent):Boolean {
                return true;
        }
    }

}

You can use your custom class in an application, as the following example shows:

<?xml version="1.0"?> 
<!-- containers\application\MainDPBMin.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    preloader="myComponents.DownloadProgressBarSubClassMin">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout> 

    <!-- Add a couple of controls that don't do anything. -->
    <s:Button label="Click Me"/>
    <s:TextInput text="This is a TextInput control."/>
</s:Application>

The executing SWF file for the previous example is shown below:

Creating an advanced subclass of the DownloadProgressBar class

In the following example, you create a subclass of the DownloadProgressBar class to display text messages that describe the status of the downloading and initialization of the application. This example defines event listeners for the events dispatched by the download progress bar to write the messages to flash.text.TextField objects.

package myComponents
{

    import flash.display.*;
    import flash.text.*;
    import flash.utils.*;
    import flash.events.*;
    import mx.preloaders.*;
    import mx.events.*;

    public class MyDownloadProgressBar extends DownloadProgressBar
    {
        // Define a TextField control for text messages 
        // describing the download progress of the application.
        private var progressText:TextField;
        
        // Define a TextField control for the final text message.
        // after the application initializes.
        private var msgText:TextField;
    
        public function MyDownloadProgressBar()
        {   
            super();

            // Configure the TextField for progress messages.
            progressText = new TextField(); 
            progressText.x = 10;    
            progressText.y = 90;
            progressText.width = 400;
            progressText.height = 400;
        
            addChild(progressText);
        
            // Configure the TextField for the final message.
            msgText = new TextField();
            msgText.x = 10;
            msgText.y = 10;
            msgText.width = 400;
            msgText.height = 75;
            
            addChild(msgText);
        }
    
        // Define the event listeners for the preloader events.
        override public function set preloader(preloader:Sprite):void {
            // Listen for the relevant events
            preloader.addEventListener(
                ProgressEvent.PROGRESS, myHandleProgress);   
            preloader.addEventListener(
                Event.COMPLETE, myHandleComplete);

            preloader.addEventListener(
                FlexEvent.INIT_PROGRESS, myHandleInitProgress);
            preloader.addEventListener(
                FlexEvent.INIT_COMPLETE, myHandleInitEnd);
        }
    
        // Event listeners for the ProgressEvent.PROGRESS event.
        private function myHandleProgress(event:ProgressEvent):void {
            progressText.appendText("\n" + "Progress l: " + 
                event.bytesLoaded + " t: " + event.bytesTotal);
        }
    
        // Event listeners for the Event.COMPLETE event.
        private function myHandleComplete(event:Event):void {
            progressText.appendText("\n" + "Completed");
        }
    
        // Event listeners for the FlexEvent.INIT_PROGRESS event.
        private function myHandleInitProgress(event:Event):void {
            progressText.appendText("\n" + "App Init Start");
        }
    
        // Event listeners for the FlexEvent.INIT_COMPLETE event.
        private function myHandleInitEnd(event:Event):void {
            msgText.appendText("\n" + "App Init End");
            
            var timer:Timer = new Timer(2000,1);
            timer.addEventListener(TimerEvent.TIMER, dispatchComplete);
            timer.start();
        }
        
        // Event listener for the Timer to pause long enough to 
        // read the text in the download progress bar.
        private function dispatchComplete(event:TimerEvent):void {
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
}

You can use your custom class in a application, as the following example shows:

<?xml version="1.0"?> 
<!-- containers\application\MainDPB.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    preloader="myComponents.MyDownloadProgressBar">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout> 
 
    <!-- Add a couple of controls that don't do anything. -->
    <s:Button label="Click Me"/>
    <s:TextInput text="This is a TextInput control."/>
</s:Application>

The executing SWF file for the previous example is shown below:

Creating a subclass of Sprite as a download progress bar

You can define a custom download progress bar as a subclass of the Sprite class. By implementing your download progress bar as a subclass of Sprite, you can create a custom look and feel to it, rather than overriding the behavior built into the DownloadProgressBar class.

One common use for this type of download progress bar is to have it display a SWF file during application initialization. For example, you could display a SWF file that shows a running clock, or other type of image.

The following example displays a SWF file as the download progress bar. This class must implement the IPreloaderDisplay interface.

package myComponents
{
    import flash.display.*;
    import flash.utils.*;
    import flash.events.*;
    import flash.net.*;
    import mx.preloaders.*; 
    import mx.events.*;
    
    public class MyDownloadProgressBarSWF extends Sprite 
        implements IPreloaderDisplay
    {
        // Define a Loader control to load the SWF file.
        private var dpbImageControl:flash.display.Loader;
    
        public function MyDownloadProgressBarSWF() {   
            super();        
        }
        
        // Specify the event listeners.
        public function set preloader(preloader:Sprite):void {
            // Listen for the relevant events
            preloader.addEventListener(
                ProgressEvent.PROGRESS, handleProgress); 
            preloader.addEventListener(
                Event.COMPLETE, handleComplete);
    
            preloader.addEventListener(
                FlexEvent.INIT_PROGRESS, handleInitProgress);
            preloader.addEventListener(
                FlexEvent.INIT_COMPLETE, handleInitComplete);
        }
        
        // Initialize the Loader control in the override 
        // of IPreloaderDisplay.initialize().
        public function initialize():void {
            dpbImageControl = new flash.display.Loader();       
            dpbImageControl.contentLoaderInfo.addEventListener(
                Event.COMPLETE, loader_completeHandler);
            dpbImageControl.load(new URLRequest("assets/dpbSWF.swf"));         
        }

        // After the SWF file loads, set the size of the Loader control.
        private function loader_completeHandler(event:Event):void
        {
            addChild(dpbImageControl);
            dpbImageControl.width = 50;
            dpbImageControl.height= 50;
            dpbImageControl.x = 100;
            dpbImageControl.y = 100;
        }   
        
        // Define empty event listeners.
        private function handleProgress(event:ProgressEvent):void {
        }
        
        private function handleComplete(event:Event):void {
        }
        
        private function handleInitProgress(event:Event):void {
        }
        
        private function handleInitComplete(event:Event):void {
            var timer:Timer = new Timer(2000,1);
            timer.addEventListener(TimerEvent.TIMER, dispatchComplete);
            timer.start();      
        }
    
        private function dispatchComplete(event:TimerEvent):void {
            dispatchEvent(new Event(Event.COMPLETE));
        }

        // Implement IPreloaderDisplay interface
    
        public function get backgroundColor():uint {
            return 0;
        }
        
        public function set backgroundColor(value:uint):void {
        }
        
        public function get backgroundAlpha():Number {
            return 0;
        }
        
        public function set backgroundAlpha(value:Number):void {
        }
        
        public function get backgroundImage():Object {
            return undefined;
        }
        
        public function set backgroundImage(value:Object):void {
        }
        
        public function get backgroundSize():String {
            return "";
        }
        
        public function set backgroundSize(value:String):void {
        }
    
        public function get stageWidth():Number {
            return 200;
        }
        
        public function set stageWidth(value:Number):void {
        }
        
        public function get stageHeight():Number {
            return 200;
        }
        
        public function set stageHeight(value:Number):void {
        }
    }
}