Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4999226
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: 系统运维

2011-09-05 00:14:37

   

ModuleManager and IModuleInfo – loading Flex Modules dynamically

When you’re working with Flex Modules, most of the time the component will be enough to get you up and running. It will quickly and easily let you load your Modules and add them to the display list, it’ll even dispatch an event to let you know when the Module is ready. Lovely stuff. It’s very similar to the SWFLoader component with some added Module-related goodness thrown in.

However, there may be times when the ModuleLoader component may not be appropriate for your needs, and you’ll have to get your hands dirty and get involved with the lower-level class. Some examples of when ModuleLoader might not be suitable include:

  • Your Module is entirely non-visual, and therefore shouldn’t be added to the display list
  • Performance is really important to your application, and the extra overhead of the ModuleLoader container is something you need to remove to try and speed things up. (ModuleLoader essentially wraps your Module’s content in an extra container, incurring a slight performance hit).
  • You need greater control over how and when your modules are loaded and unloaded.
How does ModuleManager work?

ModuleManager maintains a map of modules, indexed by each module’s URL. Information about the module is stored as an object implementing , and is retrieved by calling the ModuleManager.getModule method, passing in the module’s URL as the method’s only parameter. Once you’ve retrieved the IModuleInfo object, you can call its load method to starting loading in the module. While the module is loading, you can monitor the load progress using a variety of different events (of type ModuleEvent). Finally, when the module is loaded and available, you can create an instance of that module using someModuleInfo.factory.create ().

IModuleInfo in more detail

As mentioned above, ModuleManager maintains a mapping of URLs to modules. When you call ModuleManager’s static getModule method, it returns an object of type IModuleInfo. If you dig around within the ModuleManager class, you’ll see that this interface is implemented internally. It’s useful to know a little bit more about how you can interact with the ModuleInfo, what methods it exposes, and what events it dispatches.

There are four read-only public Boolean properties which offer information about the current state of the module. They can briefly be described:

  • IModuleInfo.error – This’ll be true if there was an error during loaded. You’re also notified of such an error by the ModuleEvent.ERROR event.
  • IModuleInfo.loaded – This will be true if you’ve previously called the IModuleInfo.load method. Note: It does not necessarily signify that the module has been loaded, just that the module load has begun.
  • IModuleInfo.setup – When enough of the module has loaded to be able to call the factory.info () method, this flag will be true. When this point in the load has been reached, a ModuleEvent.SETUP event will be dispatched.
  • IModuleInfo.ready – When enough of the module has been loaded for you to be able to instantiate an instance of the module using the factory.create () method, this flag will be true. At this stage, a ModuleEvent.READY event will be dispatched. This property will typically become true at some point after the IModuleInfo.setup becomes true.

There are some additional properties which can also be useful:

  • IModuleInfo.url fairly obviously returns the URL associated with the IModuleInfo object. This could be useful if you’re using one event handler to listen out for the events from multiple modules – the event.currentTarget.url property could be used to identify which module had sent out the event.
  • IModuleInfo.data is an object which you can use to associate data with a particular module. The data will be shared across all instances of a particular module, so this property comes in handy if you want to share state, or user information between multiple instances of the same dynamically loaded module.
  • IModuleInfo.factory is pretty important. Once the the module is ‘ready’ (after the ModuleEvent.READY event has been dispatched, or when IModuleInfo.ready returns true), you can create an instance of your module by calling the IFlexModuleFactory.create method. Additionally, once the module has been ’setup’ (after ModuleEvent.SETUP has fired, or when IModuleInfo.setup returns true), you can query the IFlexModuleFactory.info method to find out a little more about the module that has been loaded.

Next we should look at some of the methods exposed by an IModuleInfo:

  • IModuleInfo.load – This is the method you’ll call to start loading a module. You can optionally pass in information about the current ApplicationDomain and SecurityDomain if necessary. When the module is loading, events will be dispatched along the way as detailed below. Quite a nice feature here is that if the module has already been loaded, and you attempt to reload it, it’ll still dispatch the “setup” and “ready” events, meaning that you can use one set of event listener methods without needing to worry about whether the module is loading for the first time, or if it already exists in local memory. Snazzy…
  • IModuleInfo.release – This method will release the current reference to the module. Internally, when this method is called, a reference counter will be decremented. If no references to the module exist after this method has been called, it will automatically be unloaded.
  • IModuleInfo.unload – This triggers the unload of the module. It’s worth noting that if any references to the module exist, it will not be garbage collected. Also, calling this method won’t remove your module from the display list, you’ll have to do that too.

Lastly, let’s look at the events dispatched… All the events listed here are instances of ModuleEvent, and for some of the events you’ll be able to access information about the load progress through the event’s bytesLoaded and bytesTotal properties.

  • ModuleEvent.ERROR – Rather obviously, this is dispatched when an error occurs during loading. This will also be indicated by the IModuleInfo.error property returning true.
  • ModuleEvent.PROGRESS – This event is dispatched periodically during the load, giving you the chance to display a visual indication of load progress if you want. This is one of the events where the bytesLoaded and bytesTotal properties will be set.
  • ModuleEvent.SETUP – This event is dispatched when enough of the module has downloaded for you to call the IModuleInfo.factory.info method. At this point, IModuleInfo.setup will also return true. This event does not allow you to access load progress through the bytesLoaded and bytesTotal properties.
  • ModuleEvent.READY – This event is dispatched when enough of the module has downloaded for you to create an instance of the module through the IModuleInfo.factory.create method. From then on, IModuleInfo.ready will also return true. Apparently, this event is one where the bytesLoaded and bytesTotal properties should be set, although I’ve noticed that this isn’t always the case. I reckon it’s safer just to use the ModuleEvent.PROGRESS information for displaying progress information.
  • ModuleEvent.UNLOAD – This event is dispatched when the module has been unloaded. No progress information is available through the event object with this event.
A simple example

First, a basic module, SimpleModule, which does nothing more than display a label within a panel.

 

  1. SimpleModule.mxml

The the main application, which will load in this module and attach instances to a Tile control.

 

  1. Shell.mxml
  2. applicationComplete="initApp()">
  3. import mx.modules.Module;
  4. import mx.events.ModuleEvent;
  5. import mx.modules.ModuleManager;
  6. import mx.modules.IModuleInfo;
  7. protected var _moduleInfo:IModuleInfo;
  8. private function initApp():void {
  9. addToLog ("Application initialised");
  10. // create the module - note, we're not loading it yet
  11. _moduleInfo = ModuleManager.getModule("SimpleModule.swf");
  12. // add some listeners
  13. _moduleInfo.addEventListener(ModuleEvent.READY, onModuleReady);
  14. _moduleInfo.addEventListener(ModuleEvent.SETUP, onModuleSetup);
  15. _moduleInfo.addEventListener(ModuleEvent.UNLOAD, onModuleUnload);
  16. _moduleInfo.addEventListener(ModuleEvent.PROGRESS, onModuleProgress);
  17. }
  18. protected function getModuleInfo () : IModuleInfo {
  19. // return the module info
  20. return _moduleInfo;
  21. }
  22. /**
  23. * Adds output to the log
  24. **/
  25. protected function addToLog (msg:String) : void {
  26. log.text += msg + "\n";
  27. // scroll to the bottom on the next frame
  28. callLater(scrollToBottom);
  29. }
  30. protected function scrollToBottom () : void {
  31. // scroll to the bottom
  32. log.verticalScrollPosition = log.maxVerticalScrollPosition;
  33. }
  34. /**
  35. * Called when the "load" button is pressed
  36. *
  37. * Starts loading the module - when the module has been
  38. * loaded, an instance of the module will be created
  39. * and added to the tile control
  40. *
  41. **/
  42. private function loadModule () : void {
  43. addToLog ("Loading module");
  44. // load the module
  45. getModuleInfo().load();
  46. }
  47. /**
  48. * Called when the "unload" button is pressed
  49. *
  50. * Removes all the instances of the module from the
  51. * tile control, then unloads the module
  52. *
  53. */
  54. private function unloadModule () : void {
  55. addToLog ("Unloading module");
  56. // clear out all the the instances
  57. // of the module from the tile
  58. tile.removeAllChildren();
  59. // unload the module
  60. getModuleInfo().release();
  61. //getModuleInfo().un
  62. }
  63. /**
  64. * Handler for the ModuleEvent.PROGRESS event
  65. **/
  66. protected function onModuleProgress (e:ModuleEvent) : void {
  67. addToLog ("ModuleEvent.PROGRESS received: " + e.bytesLoaded + " of " + e.bytesTotal + " loaded.");
  68. }
  69. /**
  70. * Handler for the ModuleEvent.SETUP event
  71. **/
  72. private function onModuleSetup (e:ModuleEvent) : void {
  73. addToLog ("ModuleEvent.SETUP received");
  74. // cast the currentTarget
  75. var moduleInfo:IModuleInfo = e.currentTarget as IModuleInfo;
  76. addToLog ("Calling IModuleInfo.factory.info ()");
  77. // grab the info and display information about it
  78. var info:Object = moduleInfo.factory.info();
  79. for (var each:String in info) {
  80. addToLog (" " + each + " = " + info[each]);
  81. }
  82. }
  83. /**
  84. * Handler for the ModuleEvent.READY event
  85. **/
  86. private function onModuleReady (e:ModuleEvent):void {
  87. addToLog ("ModuleEvent.READY received");
  88. // cast the currentTarget
  89. var moduleInfo:IModuleInfo = e.currentTarget as IModuleInfo;
  90. // Add an instance of the module's class to the
  91. // display list.
  92. addToLog ("Calling IModuleInfo.factory.create ()");
  93. tile.addChild( moduleInfo.factory.create () as SomeModule);
  94. addToLog ("SomeModule instance created and added to Display List");
  95. }
  96. /**
  97. * Handler for the ModuleEvent.UNLOAD event
  98. **/
  99. public function onModuleUnload (e:ModuleEvent) : void {
  100. addToLog ("ModuleEvent.UNLOAD received");
  101. }
  102. ]]>

What’s going on here? Well… when the app is created, initApp is called and the IModuleInfo object is created, and various event listeners are setup. When the user clicks the load button, the module is loaded. It doesn’t matter whether this is the first time the module is loaded, or if the module is already loaded and ready, the ModuleEvent.READY event will be dispatched to let us know that the module is ready, and that we can now create an instance of it. Within the handler for the ModuleEvent.READY event, we call IModuleInfo.factory.create () and add the instance of the module to our Tile control.

When the user clicks the unload button, all instances of the Module that we’ve added to the Tile control are removed, and we call IModuleInfo.unload to unload the module. A log message from within the handler for ModuleEvent.UNLOAD demonstrates that this is happening.

Additionally, within the event handler for ModuleEvent.SETUP we show an example of the IModuleInfo.factory.info method – this’ll give you an example of the kind of information you can retrieve about the module, and from looking at the log messages you’ll be able to see the order in which these events are dispatched.

Lastly, here’s the finished example:

[kml_flashembed movie="/blog/bin/modulemanager/Shell.swf" height="400" width="600" /]

 

(Update: I’ve explained the IFlexModuleFactory class in a little more detail here.)

阅读(1760) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~