在actionscript和Flex中的大型应用程序上管理EventListener的最佳方法

时间:2012-05-29 21:02:56

标签: actionscript-3 flex garbage-collection addeventlistener event-listener

我在flex 4.5中有一个很大的移动应用程序,使用“大”我的意思是大..

  1. 50+次观看
  2. 50多个自定义组件
  3. 10多个自定义活动
  4. 50多个自定义类(不是UIComponents)
  5. 很多皮肤等...
  6. 我从未删除过EventListener,现在我正在查看flash分析器,而且我有很多内存泄漏。
    我实际上认为使用navigator.pushViewnavigator.popView()navigator.popToFirstView()将删除视图本身中所有对象/变量的任何引用并且已经收集了...

    我正在尝试修复我的代码但是我在理解如何使用事件监听器方面遇到很多问题......

    我认为如果我使用一些例子而不是描述每一个可能的案例会更容易......

    示例1:

    private function XXX():void
    {
      var x:ClassA = new ClassA();
      x.addEventListener(CustomEvent.GETA, doSomething);
      x.addEventListener(CustomEvent2.TESTB, doSomethingElse);
    }
    private function doSomething(e:CustomEvent):void{}
    private function doSomethingElse(e:CustomEvent2):void{}
    

    在触发一个eventListener后,是否需要删除它? 如果是,我是否需要在doSomething和doSomethingElse中删除这两个事件监听器?

    在addeventlistener中使用weakReference会更好吗? x.addEventListener(CustomEvent.GETA, doSomething, false, 0, true);

    示例2:

    tile是一个TileGroup,但它可能就是一切...

    protected function activate(event:ViewNavigatorEvent):void
    {               
    tile.removeAllElements();
    for (var i:int = 1 ; i < functionCount.length ; i++)
    {           
    var t:ImageButton = new ImageButton();
    t.label = "";
    switch (functionCount.getItemAt(i))
    {
        case "Val1":
            t.addEventListener(MouseEvent.CLICK,function():void{goToAgenda();});
        break;
        case "Val2":
            t.addEventListener(MouseEvent.CLICK,function():void{goToAdmin();});                                 
        break;
        case "Val3":
            t.addEventListener(MouseEvent.CLICK,function():void{goToMyStore();});                                   
            break;  
        case "Val4":        
            t.addEventListener(MouseEvent.CLICK,function():void{openBI();});
            break;  
    }
      tile.addElement(t);
    }
    

    click上的ImageButton调用了一个功能,可以执行某些操作而不是调用navigator.pushView 如果我更改视图,是否应该从每个按钮中删除每个EventListener? 哪个地方最好?

    如果我有一个包含15000个组件的视图,在删除视图时是否必须手动删除添加到每个组件的所有eventlistener ???

    修改

    我主要需要在从舞台中删除视图时删除所有事件侦听器,而不是每次我想到替代方案时手动执行它而创建一个简单的类......

    package utils {     import mx.collections.ArrayCollection;

    public class Evt
    {
        public static var listaEvt:ArrayCollection = new ArrayCollection();
    
        private var object:* = null;
        private var event:* = null;
        private var functio:* = null
    
        public function Evt(obj:*, evt:*, funct:Function)
        {
            this.object = obj;
            this.event = evt;
            this.functio = funct;
        }           
    
        public static function addEvt(obj:*, evt:*, funct:Function):void
        {
            var t:Evt = new Evt(obj, evt, funct);
            listaEvt.addItem(t);
        }
    
        public static function clear():void
        {
            var tmpArr:ArrayCollection = new ArrayCollection();
            tmpArr.addAll(listaEvt);
            listaEvt = new ArrayCollection();
            for (var i:int = 0 ; i < tmpArr.length ; i++)
            {
                var t:Evt = tmpArr.getItemAt(i) as Evt;
                if (t.object != null && t.event != null && t.functio != null)
                {
                    if (t.object.hasEventListener(t.event))
                        t.object.removeEventListener(t.event, t.functio);
                }
            }
        }
    }
    }
    

    在我的代码中随时我不需要弱引用我也调用(也使用匿名函数):

    // t can be any component with a event associated...
    var f:Function = function():void{navigator.pushView(FotoGallery,data);};
    Evt.addEvt(t, MouseEvent.CLICK, f);
    t.addEventListener(MouseEvent.CLICK,f);     
    

    然后当我进入一个新视图时,我做了一个简单的Evt.clear(); 这种方法有效吗?有任何建议改善/改变它吗?

1 个答案:

答案 0 :(得分:1)

最终,较大的应用程序可能会从Swiz FrameworkPure MVC等框架中受益,这些框架可以提供帮助:

  • 控制/依赖注入的反转
  • 事件处理和调解
  • 异步远程方法的简单生命周期
  • 与应用程序代码分离的框架
例如,Swiz可以使用元数据标签来调解事件,从显示列表中捕获事件或为源自非UI源的事件注入调度程序。

[Dispatcher]
public var dispatcher:IEventDispatcher;

[EventHandler( event="UserEvent.ADD_USER" )]
public function handleAddUserEvent( event:UserEvent ):void
{
    // do stuff
}

否则,如上所述,事件侦听器中的弱引用是一个选项:

addEventListener(Event.COMPLETE, completeHandler, false, 0, true);

需要隔离事件处理的视图可以适应从阶段添加和删除的内在生命周期。当显示对象准备好处理来自显示列表的信号时,在addedToStage上添加侦听器,并在显示对象不再需要事件处理时在removedFromStage上配置侦听器。

package
{
    import flash.display.Sprite;
    import flash.events.Event;

    public class MyClass extends Sprite
    {
        public function MyClass()
        {
            super();

            addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        }

        protected function addedToStageHandler(event:Event):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
            addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);

            /* add event listeners here */
        }

        protected function removedFromStageHandler(event:Event):void
        {
            removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
            addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);

            /* remove event listeners here */
        }

        protected function dispose():void
        {
            /* any remaining cleanup */
        }

    }
}