Modular Popups Round 2

beaubrewer's Avatar

beaubrewer

25 Oct, 2013 06:48 PM

I'm back after a long break from Flex. Needless to say, it's good to be back in the company of Robotlegs 2 and Flex. Here's a previous post when I was initially exploring popup modules for reference.

I've been working on an application that loads modules (within a command) and uses the PopupManager to present them. Each module has their own context, custom styles, etc. My first attempt at this ended up with a terrible memory leak. My popups were getting pinned in memory. Each time the parent application command to display the popup was called, it would create a new instance and memory usage would increase. This was happening with the -keep-all-type-selectors compiler flag.

At this point, I thought it might be better to cache the popup as suggested here
This seems easy enough, but by having the popup a module... there are some additional considerations that I have been trying to wrap my head around. One issue I've run into is that the context is destroyed automatically when you call PopupManager.removePopup(popup);
This is problematic if your module creates the context within a preinitialize handler as many do. The popup is cached, thus preinitialize doesn't run the next time you call PopupManager.addPopup(popup); and nothing gets mapped.

Here's some code snippets:

CheckoutCommand

override public function execute():void {
    if(PopupCache.checkoutLoaded) {
        viewManager.addContainer(PopupCache.checkoutPopup as DisplayObjectContainer);
        PopUpManager.addPopUp(PopupCache.checkoutPopup, FlexGlobals.topLevelApplication as DisplayObject, true);
        PopUpManager.centerPopUp(PopupCache.checkoutPopup);
    } else {
        //create the checkout module
        info = ModuleManager.getModule("com/modules/checkout/views/CheckoutModule.swf");
        info.addEventListener(ModuleEvent.READY, onCheckoutModuleLoaded);
        info.addEventListener(ModuleEvent.ERROR, onCheckoutModuleError);
        info.load();
    }
}
private function onCheckoutModuleLoaded(event:ModuleEvent):void
{
    //trace("loaded checkout module");
    PopupCache.checkoutPopup = info.factory.create() as IFlexDisplayObject;
    viewManager.addContainer(PopupCache.checkoutPopup as DisplayObjectContainer);
    info.removeEventListener(ModuleEvent.READY, onCheckoutModuleLoaded);
    info.removeEventListener(ModuleEvent.ERROR, onCheckoutModuleError);
    PopUpManager.addPopUp(PopupCache.checkoutPopup, FlexGlobals.topLevelApplication as DisplayObject, true);
    PopUpManager.centerPopUp(PopupCache.checkoutPopup);
}
private function onCheckoutClose(event:CloseEvent):void
{
    //This isn't currently being called. The CheckoutModuleMediator is currently
    //removing it (see below)
    PopUpManager.removePopUp(PopupCache.checkoutPopup);
    viewManager.removeContainer(PopupCache.checkoutPopup as DisplayObjectContainer);
}

CheckoutModuleMediator

public class CheckoutModuleMediator extends Mediator
{
    [Inject] public var view:CheckoutModule;
    [Inject] public var model:StoreFrontCheckoutModel;
    [Inject] public var viewManager:IViewManager;
    
    private var resourceManager:IResourceManager;
    private var checkoutStates:Array;
    
    public function CheckoutModuleMediator()
    {
        super();
        resourceManager = ResourceManager.getInstance();
        checkoutStates = [
        resourceManager.getString('Checkout','shipping_details'),
        resourceManager.getString('Checkout','billing_information'),
        resourceManager.getString('Checkout','place_order')
        ];
    }
    
    override public function initialize():void
    {
        addViewListener(CloseEvent.CLOSE, onClose);
    }
    
    override public function destroy():void
    {
        removeViewListener(CloseEvent.CLOSE, onClose);
        super.destroy();
    }
    
    private function onClose(event:CloseEvent = null):void
    {
        PopUpManager.removePopUp(view);
    }
}

I was able to get things to work by creating the context within an addedToStage handler. While this works, my intuition says there is a better way. (maybe not)

(update) I just read a post that stated the Debugger / Profiler has a bug and will always show a memory leak for modules. Is this still the case?

Is there a way to cache a popup and not kill the Context each time it's removed via the PopupManager? It seems like the benefits of not having to create/destroy objects each time the popup is shown would make sense here. Maybe I just need a cheat sheet on manually managing mediators / contexts / etc.

  1. Support Staff 1 Posted by Shaun Smith on 26 Oct, 2013 01:07 PM

    Shaun Smith's Avatar

    Hiya,

    Here's how the context gets destroyed when it leaves the stage:

    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

    So, you could avoid auto destruction by making your own clone of the MVCSBundle - one that doesn't include the StageSync Extension.

    Hope that provides some clues :)

  2. Ondina D.F. closed this discussion on 15 Nov, 2013 11:45 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac