Flex 3 runtime loading with RSLs and Modules
Before I start I know a lot of people just want to see demos so here are links to the two demos I have. They can also be found later on in this post.
I wanted to load code into my Flex application during runtime instead of compiling it into my app. I was not quite sure how to go about doing this and many google searches revealed nothing. At this point I was not even sure it was possible but after much research and playing around I came up with what I think is a pretty decent way of doing this and decided that I should share it with everyone. I created a couple sample applications to show how this can work and enabled the source so you can see exactly what is going on. There are two examples one that makes use of Modules (my personal choice) and one that uses RSLs. Read more about both below.
Why not just compile everything into your app?
Recently I was working on a project that was basically made up of a number of smaller components. Users would be able to select and add components to it during runtime. Also new components would be released periodically and I did not want to have to rebuild the application every time a new component was released. The app would be able to get information about all of the components from a database so the application would know that these new components existed. I just needed to come up with a good way to load them. I considered several options such as compiling each component into its own swf. I could then load each swf as I needed it. This method seemed kind of dirty plus I wanted a way to load actual classes and be able to instantiate them my self. I decided to figure out a way that I could load code into the application during run time similar to how a dll can be loaded during a programs execution. This would give me a couple of benefits:
- The ability to load and use classes not built into the main application at compile time
- Separation of code into different swfs
- Make code changes with out recompiling the entire application
- Faster application load times
- Save bandwidth by loading only the code you need when you need it
- Provides an easy way to add extend and add to an application
Now you might be thinking “Haven’t you ever heard of runtime-shared libraries?” Indeed I have heard of runtime-shared libraries and used them numerous times. In fact my first attempt to this runtime loading was with RSLs and it worked alright but it was not quite what i wanted. See my example below.
Usually runtime-shared libraries are used to tell Flash Player to cache certain libraries so they do not need to be loaded everytime your app is loaded: They are also used so that multiple apps can share common code. This works by telling Flex which libraries you want to load as runtime-shared libraries. Then your application gets compiled with out them and you compile them as runtime-shared libraries with mxmlc. The libraries are then loaded the first time you run the app and cached by the Flash Player (if they are signed). The next time the application loads it will not need to reload those libraries as they are cached. This make the first application load a little slower but subsequent loads can be much faster, especially when you cache the Flex frame work. Even if your RSLs are not signed this still allows you to make code changes once and not have to recompile all of your apps just the one RSL that changed.
That being said it is possible to load runtime-shared libraries on demand during runtime, not just at the very beginning. The classes they contain can then be used just as if they where at compiled into the application.
This is the first method I tried to use but soon found it difficult to compile the components because of different dependencies for each one. I put together a couple prototypes using RSLs and ran into some problems: Most of the time it was missing dependences. For example one of the components was a Button but I had problems getting the halo.skins package into the RSL and thus caused runtime errors. I imagine most of these were caused by the way I was building the RSLs but I decided to see if there was an easier way.
Loading RSLs on the fly example (View Source Enabled)
To load an RSL at runtime you just have to use a Loader with a LoaderContext to load the RSL into your main applications ApplicationDomain. I have enabled view source on this example also.
Modules and the ModuleManager
After doing a little more searching I remembered a little thing called Module. Modules are specifically meant to be loaded at runtime and they are super easy to build. They also can be optimized similarly to how you can choose what packages you build into an RSLs. After reading the documentation I decided that Modules might the way to go.
Most of the time Modules are used to load complex forms or other large components at runtime to help cut down applications initial load. Using the mxml ModuleLoader you are able to load and unload these Modules and then use them just like any other UIComponent. You can also use the ModuleManager class to load a Module if you require a little more control. The ModuleManager returns an IModuleInfo which can be used to create and instance of the Module.
Close but not quite what I was after
This was great but I wanted to be able to load any type of code at runtime not just a Module, which is a UIComponent. I wanted to be able to load and use class references so I could do instantiation my self. I had an idea that would still use Modules but the Modules that I loaded would really act as a factory. This factory could then return what ever it was I really wanted. This would allow me to load anything: It could be a UIComponent, a Class, or any other type of object, not just a Module.
What I came up with
I ended up building a class called DynamicFactory which has a public method createFromModule. This method loads a module that implements IFactoryModule and then returns what ever it was that you really wanted. This method takes 2 parameters type (the type to create) and moduleUrl (the location of the Module to use). This setup is very flexible because I can return both instances and classes from the Module. Also having multiple components in one Module gives some performance increases over having a separate Module for each component. This is because once a Module is loaded subsequent creations from it do not have to reload the Module.
DynamicFactory example (View Source Enabled)
In this example the Module urls and the types that they can create are hard coded into the application. In a real situation these values would come from a database or some other source. This would allow the application to use new components as they are created. Also note that once a module is loaded creating another component from the same module does not cause the module to be loaded again. The ModuleManager is smart enough to know which Modules are loaded.
I would guess that most of the time, most people could satisfy their needs using just the Module and ModuleBase Classes. I had some specific needs and that is why I created the DynamicFactory Class but I would first recommend trying to use the stuff that Flex already provides.