Flex 4 has introduced a new preloader and with it a series of new events that we can leverage. I am not going to take much time explaining how to build a preloader, there are some solid examples out there to cut your teeth on. The first example is Adobe's official documentation.
The issue with this documentation is that it ignores the Runtime Shared Library (RSL) progress events dispatched by the preloader instance. Its briefly mentioned in the Events list, but never used in the code. The challenge is that the basic progress events change drastically based on the current RSL being loaded.
By default, Flex 4 now breaks the SDK into multiple RSLs (SWF & SWZ), this means that we have to track n number of RSLs at load time and this cascades down into both the RSL progress and the init progress. The change in RSL requirements creates some interesting challenges in how we have to calculate the current progress and also causes some odd behavior with our loader. Let's take a look at the following diagram to see how the Flash player loads the content and what events are dispatched.
The goal of an RSL is to compartmentalize code in a downloadable file that can be cached and individually updated without requiring the entire project to be re-compliled (more or less). The new Flex 4 RSL structure for the framework is intended to break out different elements of the SDK into separate RSL files to allow developers to only require the RSLs they use in the project, and to allow the player to cache the files so the user only has to download them once.
If you are creating a Flex application using all the features of Flex 4, you will have seven files that are required to be downloaded and then loaded into the player. The main SWF (your application code) and the six Flex 4 RSLs: framework, osmf_flex, rpc, spark, sparkskins, and textLayout. All of these files must be loaded and initialized before you application is started and we can reflect this process in the custom preloader. If you add more RSLs, custom libraries, etc; then you will have to load even more files before the application can begin.
There are few preloader events that we want to track during our load process: ProgressEvent.PROGRESS, RSLEvent.RSL_PROGRESS, RSLEvent.RSL_COMPLETE, FlexEvent.INIT_PROGRESS and FlexEvent.INIT_COMPLETE. All these events are dispatched during the loading process, and the order they get called in changes based on what action is being taken. This can create a really confusing order of operation.
The ProgressEvent.PROGRESS event is dispatched as the main application SWF is being loaded and as RSLs are being loaded. This means that the total bytes and the loaded bytes in the ProgressEvent.PROGRESS event changes depending on where we are in the load process. The problem is that most examples just use the ProgressEvent.PROGRESS event to calculate the percent based on the total and loaded values.
What we experienced in a current project I am working on is that the loader bar would jump around from complete to partially loaded back to complete as each of these progress values are updated. This lead me to start researching into the different events and found out about the RSLEvent.RSL_PROGRESS and RSLEvent.RSL_COMPLETE events.
Bernhard Hirschmann has an example
(make sure to view the source) that taps into the RSL download events, but his solution only shows the basics for tracking and calculating a single RSL. Seth Duffy also has a good demo
, but once again he is not handling multiple-RSL loads.
The RSLEvent.RSL_PROGRESS is dispatched as a specific RSL is being loaded into the player and gives us bytes loaded and total, so that we can calculate a percentage. When the RSL is done loading the RSLEvent.RSL_COMPLETE is dispatched. The problem is that ProgressEvent.PROGRESS events are randomly mixed into the RSLEvent.RSL_PROGRESS events and this creates a lot of confusion. Luckily, Bernhard's example (mentioned above) handles the mixing of RSLEvent.RSL_PROGRESS and ProgressEvent.PROGRESS for us.
Once I tied our project into the RSLEvents, we still were not getting a seamless load experience, because the progress would start back at zero once the next RSL started loading (not including the SWF load calculation that Bernhard shows). After a bit more digging, I found out that the RSLEvent has two properties, rslIndex and rslTotal. These properties tell us which RSL is being loaded and how many we have to load. Knowing this information we can calculate what percentage we are currently at using the bytesLoaded, totalBytes, rslIndex and rslTotal.
At this point I had to do a little (okay a lot) of hacking to get the right calculation, because I suck at math. BUT, I am persistent and I usually can figure it out. Here is the code (the event is the RSLEvent.RSL_PROGRESS):
Math.round(((event.bytesLoaded / event.bytesTotal) + event.rslIndex) / event.rslTotal * 100);
This allows us to calculate the current percentage of the RSL download based on both the current bytes and the position within the RSL index.
The result is the ability to create a smooth 0 - 100% progress bar for all our SWF and RSL files, no matter how many RSLs we have attached to our application.
One other thing to note, is that once the SWF and RSLs are loaded they need to be initialized. The final event we can track is the FlexEvent.INIT_PROGRESS event. This is not your typical progress event, because it does not provide bytesLoaded vs. bytesTotal. This is just dispatched as each part (SWF/RSL) is being initialized.
We can determine how many times FlexEvent.INIT_PROGRESS will be called by storing the total number of RSLs plus one (each RSL and the main SWF application). Using this value we can then increment the progress bar by a small amount as each FlexEvent.INIT_PROGRESS is dispatched and allow us just a bit more granularity into the preloader.
I hope this post helps some of you out there, I know that making a smooth loader was a bit of a challenge, but once you get all the parts its not too bad.