Tutorials, Videos

Custom Flex 4 preloader

26 Comments 25 August 2010

Custom Flex 4 preloader

Yesterday, I started coding a Flex 4 application for an event in November. Being fed up with the classic Flex 4 progress bars, I decided to create a custom one using Flash CS5 and Flash Builder 4. I was surprised by the lack of tutorials on this topic, so that’s why I’m writing this post today. First, I need to mention this excellent tutorial written by Seth. It’s the only sample I’ve found so far that uses a Flash CS file to customize the user experience. My custom preloader is inspired by this tutorial. The tricky part of this development was to understand correctly the behavior of the Flash Player while loading a Flex 4 application. First, the Flash Player loads the SWF application file (e.g. main.swf). As it discovers that it’s a Flex 4 application, it needs to download the RSLs of the appropriate framework. Framework RSLs come in two versions: signed and unsigned. If you publish an application with signed RSLs, then they can cached in a special Flash Player space and in the browser cache (if you clear the browser’s cache, then the RSLs still persist in the special Flash Player cache). If you publish a Flex 4 application with unsigned framework RSLs, then they are cached in the browser cache only and can only be used by applications coming from the same domain.

This can dramatically change the final users’ experience while loading your Flex 4 application. I’ve developed a classic Flex 4 sample and published it with unsigned RSLs. The Flash Player starts loading the main.swf, then the RSLs (OSMF, TLF,framework,spark, rpc and sparkskins). I’ve noticed that it can be a parallel download. The player starts downloading the unsigned RSLs even if the download of the main application is not over. That’s why the progress bars of the classic Flex 4 preloader might display unexpected behaviors: the bar progresses then goes back, then progresses again or flickers. It’s due to the implementation of the SparkDownloadProgressBar that uses two tracks. The first track (a grey rectangle in the background of the progress bar) shows the download progress. The second one shows the Initialization progress. I wanted to extend this class for several reasons. The Download progress tracks displays mixed information: the download progress of the main application, and also the RSLs one. The good news is that you can override two separate progress handlers: progressHandler for the main app, and rslProgressHandler, so that you can see and feel these two steps separately. Another finding is that the new SparkDownloadProgressBar doesn’t display any text information (which was the case with Flex 3).

Before sharing my code, let’s see together the final result. If you wish to test it, clear your browser’s cache and click on these links:
- Link to the application with unsigned RSLs: the Flash Player will load the main application plus six RSLs.
- Link to the application with signed RSLs: the Flash Player should only load the main application and get the RSLs from the Flash Player’s cache. You can right-click the application and download the source code (the FLA of the preloader animation is included).

Flex 4 custom preloader from michael chaize on Vimeo.

As you can see, I’m not using the classic progress bar anymore but a custom Flash animation. The white logo appears when the main application is loaded. The AS3 function that controls the white logo is setMainProgress(). Then the stroke of the logo (plus a glow effect) appears while the RSLs are loaded. The AS3 function is setDownloadRSLProgress() in this case. Finally the red square fades out while the initialization step (setInitAppProgress function).

Then I publish the Flash CS5 animation to obtain a SWC component that I can import into my Flash Builder 4 project. To use and pilot this animation, you need to extend the SparkDownloadProgressBar class. Then you’re free to override the classic behavior of methods such as setDownloadprogress, rslProgressHandler or progressHandler. Just remember that when the rslProgressHandler method is called, you can get the total number of RSL to load for your application. To display the global progress download of the RSLs, you must use this function: Math.round(i*100/t + a/t) where i is the current index of the loaded RSL, t is the total number of RSLs and a the progress download status of the RSL. In my sample, preloaderDisplay is the name of the Flash component. Here is the code of my custom Spark Progress Bar component:

/*
* Class blogged on RIAgora.com
* Inspired by http://www.leavethatthingalone.com/blog/index.cfm/2009/11/11/Flex4CustomPreloader
*/
 
package com.riagora.loader
{
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.utils.getTimer;
 
	import mx.events.RSLEvent;
	import mx.preloaders.SparkDownloadProgressBar;
 
	public class Preloader extends SparkDownloadProgressBar
	{
 
		private var _displayStartCount:uint = 0;
		private var _initProgressCount:uint = 0;
		private var _downloadComplete:Boolean = false;
		private var _showingDisplay:Boolean = false;
		private var _startTime:int;
		private var preloaderDisplay:PreloaderDisplay;
		private var rslBaseText:String = "Loading app: ";
		private var numberRslTotal:Number = 1;
		private var numberRslCurrent:Number = 1;
 
		public function Preloader()
		{
			super();
		}
 
		/**
		 *  Event listener for the <code>FlexEvent.INIT_COMPLETE</code> event.
		 *  NOTE: This event can be commented out to stop preloader from completing during testing
		 */
		override protected function initCompleteHandler(event:Event):void
		{
			dispatchEvent(new Event(Event.COMPLETE));
		}
 
		/**
		 *  Creates the subcomponents of the display.
		 */
		override protected function createChildren():void
		{
			if (!preloaderDisplay) {
				preloaderDisplay = new PreloaderDisplay();
 
				var startX:Number = Math.round((stageWidth - preloaderDisplay.width) / 2);
				var startY:Number = Math.round((stageHeight - preloaderDisplay.height) / 2);
 
				preloaderDisplay.x = startX;
				preloaderDisplay.y = startY;
				addChild(preloaderDisplay);
			}
		}
 
		/**
		 * Event listener for the <code>ProgressEvent.PROGRESS event</code> event.
		 * Download of the first SWF app
		 **/
		override protected function progressHandler(evt:ProgressEvent):void {
			if (preloaderDisplay) {
				var progressApp:Number = Math.round((evt.bytesLoaded/evt.bytesLoaded)*100);
 
				//Main Progress displays the shape of the logo
				preloaderDisplay.setMainProgress(progressApp);
 
				setPreloaderLoadingText(rslBaseText + Math.round((evt.bytesLoaded/evt.bytesLoaded)*100).toString() + "%");
			}else{
				show();
			}
		}
 
		/**
		 * Event listener for the <code>RSLEvent.RSL_PROGRESS</code> event.
		**/
		override protected function rslProgressHandler(evt:RSLEvent):void {
			if (evt.rslIndex && evt.rslTotal) {
 
				numberRslTotal = evt.rslTotal;
				numberRslCurrent = evt.rslIndex;
				rslBaseText = "loading RSLs (" + evt.rslIndex + " of " + evt.rslTotal + ") ";
 
				var progressRsl:Number = Math.round((evt.bytesLoaded/evt.bytesTotal)*100);
 
				preloaderDisplay.setDownloadRSLProgress(Math.round( (numberRslCurrent-1)*100/numberRslTotal + progressRsl/numberRslTotal));
 
				setPreloaderLoadingText(rslBaseText + Math.round((evt.bytesLoaded/evt.bytesTotal)*100).toString() + "%");
			}
		}
 
		/**
		 *  indicate download progress.
		 */
		override protected function setDownloadProgress(completed:Number, total:Number):void {
			if (preloaderDisplay) {
				//useless class in my case. I manage the display changes directly in the Progress handlers
			}
		}
 
		/**
		 *  Updates the inner portion of the download progress bar to
		 *  indicate initialization progress.
		 */
		override protected function setInitProgress(completed:Number, total:Number):void {
			if (preloaderDisplay) {
				//set the initialization progress : red square fades out
				preloaderDisplay.setInitAppProgress(Math.round((completed/total)*100));
 
				//set loading text
				if (completed > total) {
					setPreloaderLoadingText("ready for action");
				} else {
					setPreloaderLoadingText("initializing " + completed + " of " + total);
				}
			}
		} 
 
		/**
		 *  Event listener for the <code>FlexEvent.INIT_PROGRESS</code> event.
		 *  This implementation updates the progress bar
		 *  each time the event is dispatched.
		 */
		override protected function initProgressHandler(event:Event):void {
			var elapsedTime:int = getTimer() - _startTime;
			_initProgressCount++;
 
			if (!_showingDisplay &&	showDisplayForInit(elapsedTime, _initProgressCount)) {
				_displayStartCount = _initProgressCount;
				show();
				// If we are showing the progress for the first time here, we need to call setDownloadProgress() once to set the progress bar background.
				setDownloadProgress(100, 100);
			}
 
			if (_showingDisplay) {
				// if show() did not actually show because of SWFObject bug then we may need to set the download bar background here
				if (!_downloadComplete) {
					setDownloadProgress(100, 100);
				}
				setInitProgress(_initProgressCount, initProgressTotal);
			}
		}
 
		private function show():void
		{
			// swfobject reports 0 sometimes at startup
			// if we get zero, wait and try on next attempt
			if (stageWidth == 0 && stageHeight == 0)
			{
				try
				{
					stageWidth = stage.stageWidth;
					stageHeight = stage.stageHeight
				}
				catch (e:Error)
				{
					stageWidth = loaderInfo.width;
					stageHeight = loaderInfo.height;
				}
				if (stageWidth == 0 && stageHeight == 0)
					return;
			}
 
			_showingDisplay = true;
			createChildren();
		}
 
		private function setPreloaderLoadingText(value:String):void {
			//set the text display in the flash SWC
			preloaderDisplay.loading_txt.text = value;
		}
 
	}
}

To use this preloader class in your main application, just use the preloader property of the main application tag: <s:Application preloader=”com.riagora.loader.Preloader”>. To download the source code of the application, run this sample and right-click to view and download the source: http://riagora.com/pvt_content/preloader/Flex4pureLoad.html

Post to Twitter

Your Comments

26 Comments so far

  1. Seth says:

    Nice tutorial!

  2. abavisg says:

    Hi Michael,

    very good post.
    I have few questions though…

    First of all as I understand it makes sense to publish with signed RSL’s as they are cached on FP.

    Now I have tested several times the 2 loading processes and noted the timings.
    I throttled my speed woth Charles to 512Kbps (and my borwser cache is always disabled).

    Unsigned:
    Tha preloader appears from 0-3 secs.
    Then from 0-3 the app is preloaded and I see the percentage going from 0-100.
    Now until the timer reaches 1 min and 22 secs (aprox) the preloader fills up and the RSL’s are loading and the process is displayed (1 of 6 etc)

    Signed:
    Tha preloader appears from 0-3 secs.
    Then from 0-3 the app is preloaded and I see the percentage going from 0-100.
    Then the weird is that the preloader freezes until the 45th sec (aprox).

    Now the unsigned process performs in an expected manner, loading the app first, then RSL’s, then the app appears.

    But the signed one the process freezes for aprox 30 secs before finally appearing.
    Is this an expected result?
    I would expect that the app will preload first form 0-100 and then if no RSL’s are needed then the app will appear with no big delays.

    many thanks

    G

  3. admin says:

    Thx Seth, and again, thank you for YOUR tutorial :)

  4. admin says:

    Hi and thank you for this test. Indeed, that’s an unexpected behavior ! wow ! 30 seconds to load the RLSs ? I don’t get why it’s due to the bandwidth. Maybe the software you use to limit the bandwidth, also limits it when you load assets locally ! It looks like Charles limits to 512Kbps the loading process of the local RSLs, cached in the Flash Player (or in your browser’s cache). Damned Charles !

  5. abavisg says:

    Actually i just tested the signed process again but with no throttling (Charles closed) and it froze for about 10 secs.
    And anyway in Charles shows that during this time the swf is downloaded not the RSL’s and it’s like this:

    http://www.riagora.com/pvt_content/preloader/Flex4pureLoad.swf

    But 10 secs in a fast internet connection (company’s broadband) is a long time even
    for RSL;s

    In some cases though it just jumps before reaching the 100% and displaying the app.

    Weird stuff…

    G

  6. admin says:

    Then there’s something wrong locally with the access to the cache of the Flash Player… weird weird weird… bizarre bizarre. Let me look for similar experiences.

  7. sriikanth says:

    Can I change swc file to update with my logo and design (font,color…..) . If possible please let me know how I can change swc and fla files

    Thanks in advance

  8. admin says:

    The FLA is inside the source code of the flex project. Open it with Flash CS, change the design, and then compile the project to generate a new SWC file.

  9. Khalil Mohammed Shams says:

    Lee Brimlow did a custom preloader tutorial too. http://www.gotoandlearn.com/play.php?id=108

  10. Juris Andersons says:

    Hi! I am new to Flex and Flex4, I wonder, how to limit bandwith in Flex project for testing purposes. I know, that there is such a functionality in Flash Professional. Thank you.

  11. Guizmo says:

    Hi,

    I’m fairly new to flex and I have an issue with your tutorial. I don’t think it’s a misunderstanding because even the examples you put online have this weird behaviour : the text is always set to 100% (on the both links you gave).

    I tried to include something larger (20Mo) and run it on my server, but the behaviour is the same. I’ve looked at the code but unfortunately I cannot figure it out.

    I’m running Firefox 3.6.13, the flash plugin is the 10.1.53.64 and I’m working under windows 7.

    Can somebody provide me an explanation because I’m stuck at the very first point (even the demo on this site doesn’t work at all)

    Thank you,

    Guiz

  12. Guizmo says:

    I forgot to mention : I’ve cleared my cache and everything …

  13. Ben says:

    Thanks very much for your detailed tutorial! Grabbed the source and just about to give it a whirl.

  14. CoDeRs says:

    Thank you for the tutorial but i seem to be having a problem with the AS file.

    private var preloaderDisplay:PreloaderDisplay;

    Description Resource Path Location Type
    1046: Type was not found or was not a compile-time constant: PreloaderDisplay. Preloader.as /Flex4pureLoad.html/src/com/riagora/loader line 25 Flex Problem

    Any help would be great, Thanks

    -Cody

  15. Mustafa says:

    hey Michaël,

    Thanks for the post first of all, its a really useful guide..
    But I have got an issue following your sample. I created my own movieClip with 100 frames on CS5 and embedded in flex as you’ve shown here. It all works great, but only in debug (/bin-debug) mode. I even uploaded files in debug mode to a test server and it works fine. But if I get a release build in Flash Builder and upload to production server, I just see the first frame, no progress at all..

    has anyone faced that issue ?

    best regards, Musti.

  16. Kenny Yates says:

    Great tutorial and some valuable information about using the preloader in Flex 4.
    I saw the issue with the flicker in the standard Fx# preloaders we have been using for years.
    This looks like it will solve the problem.
    Thanks,
    Kenny

  17. Marylka says:

    Hi Michael.

    THX. Great tutorial :]

  18. Ana says:

    Bonjour Michaël
    Can you please answer CoDeRs’s question
    I had the same problem b4, I will try this tutorial and hopefully I will be able to do it…
    Thanks

    Ana

  19. Rahul says:

    Hi,
    can u help me about preloader,
    I want to load multiple httpservice on preloader

    thankyou

  20. Seppe Staes says:

    Is there a way to export the swc from Flash without including the fl.managers ?

    We’ve had conflicts (inconsistent behavior) with the mx.managers.FocusManager in Flex (swc includes fl.managers.FocusManager)

    Removing the preloader solved the problem.

    Any ideas? Thx.

  21. Pushpa says:

    Hi Michaël,

    I am facing same issue like Mustafa. I am able to see rsl loading animation in debug mode but animation is not seen in release build. Please tell me how to solve this issue.

    Thanks.

  22. Ged says:

    I have an issue with this preloader not firing the complete event to the Flex app – only in Safari on the MAC.

    We’re not using RSLs so have removed that aspect. Works fine in Flash 10 Windows.

    Advice, Anyone else?
    Thanks.


Trackbacks/Pingbacks

  1. Localisation, Mike Chambers et AIR « Code moi un mouton - September 3, 2010

    [...] aussi plongé dans deux sujets pour l’occasion. Le preloader Flex 4 personnalisé avec Spark: http://www.riagora.com/2010/08/custom-flex-4-preloader/ et la création d’un badge d’installation automatique d’une application AIR: [...]

  2. Custom Flex 4 preloader | TMHs Web Tips - September 20, 2010
  3. Adobe Flash y Actionscript 3 » [Flex] Precarga personalizada en Flex 4 (Spark Template) - January 9, 2011

    [...] click a este Enlace y ya lo tienes [...]

  4. blog » Closing Custom Preloader from Flex Application - January 31, 2012

    [...] There are tons of great tutorials how to customize a preloader such as this one for Flex 4.0 http://www.leebrimelow.com/?p=916 or http://www.riagora.com/2010/08/custom-flex-4-preloader/ [...]

Share your view

Post a comment

Who am I ?

I'm Michaël CHAIZE, Adobe Flash Platform Evangelist based in Paris. I'm a big fan of Rich Internet Applications and I promote the Flash Platform in the Enterprise world.
You can follow me on twitter: http://twitter.com/mchaize

Magazine

Follow us on Facebook

© 2014 RIAgora. Powered by WordPress.

Daily Edition Theme by WooThemes - Premium WordPress Themes