清除文件引用对象上的事件监听器

时间:2010-06-16 21:33:22

标签: actionscript-3 actionscript event-listener filereference

我有一个奇怪的问题!我试图通过调用一个函数来删除FileReference对象上的事件监听器,但它似乎没有被删除,我不明白为什么。

以下是代码:

private function clearFileUploadListeners(file:FileReference, index:String):void {
    var dispatchEvent:Function = function(event:Event):void {
        dispatch(event.type, event, index);
    };

    file.removeEventListener(Event.COMPLETE, dispatchEvent);
    var bool:Boolean = file.hasEventListener(Event.COMPLETE);
    if (bool)
        trace("ERROR");
}

当我运行此代码时,实际发生了跟踪。我不明白为什么这个布尔值返回true,当我试图删除上面的eventListener时!我想我可能正在做一些非常愚蠢的事情,因为这似乎是一个奇怪的错误。

我希望有人可以帮我解决这个问题。

编辑:

我认为这与我在添加监听器时在另一个函数中定义dispatchEvent函数的事实有关:

private function upload(file:FileReference, index:String):void {
    var dispatchEvent:Function = function(event:Event):void {
        dispatch(event.type, event, index);
    };

    file.addEventListener(Event.COMPLETE, dispatchEvent);
}

问题是我需要从侦听器访问这个“索引”变量,我不能将它设置为全局变量,因为每个文件都有它自己的索引,如果我必须扩展每个事件类,这是一个负担跟踪索引(Event,ProgressEvent,..)。我希望有人可以帮助我。

EDIT2:

我实际上找到了一个临时解决方案,我不确定它是否是最好的!我把removeListener方法实际放在upload方法中,但是把它变成了一个变量。由于AS3允许动态对象,我将此方法附加到我的一个对象,因此我只需在必要时调用对该方法的引用。该事件实际上已被删除。这是一个很好的解决方案吗?

非常感谢, 鲁迪

2 个答案:

答案 0 :(得分:1)

你是对的,它与你在另一个函数中定义函数,然后用它来处理事件这一事实有关。

每次调用函数upload时,它都会创建一个新的closure,并将其引用分配给dispatchEvent变量,然后将其传递给addEventListener }类。因此,每次调用upload时,它都会在调用addEventListener时使用新的不同的闭包。类似地,在clearFileUploadListeners函数中,每次调用都会创建一个新的闭包(每次碰巧都有相同的代码,但它们不是同一个函数对象)。如果给定的回调没有被添加为给定事件的事件监听器,则对removeEventListener的调用不执行任何操作,这就是这种情况。

要解决您的问题,您需要存储对传递给addEventListener函数的闭包的引用。这样,您可以获得对稍后需要在clearFileUploadListeners中删除时添加的相同闭包的引用。

您可以尝试以下代码(未经测试):

import flash.utils.Dictionary;

var callbackRegistry:* = new Dictionary();


private function upload(file:FileReference, index:String):void {
    var dispatchEvent:Function = generateFileUploadCompleteCallback();

    callbackRegistry[file] = dispatchEvent;

    file.addEventListener(Event.COMPLETE, dispatchEvent);
}

private function clearFileUploadListeners(file:FileReference, index:String):void {
    var dispatchEvent:Function = callbackRegistry[file];
    callbackRegistry[file] = null;

    file.removeEventListener(Event.COMPLETE, dispatchEvent);

    var bool:Boolean = file.hasEventListener(Event.COMPLETE);
    if (bool)
        trace("ERROR");
    else
        trace("YAY, ALL OK!");
}

private function generateFileUploadCompleteCallback(index:String):Function {
    return function(event:Event):void {
        dispatch(event.type, event, index);
    };
}

答案 1 :(得分:0)

关于这个主题还有两点需要注意。

如果您必须直接使用本机事件,那么您应该总是确保并使用这最后三个可选参数:

myObject.addEventListener( Event.COMPLETE, myFunction, false, 0, true );

在此处查看Grant Skinner关于此主题的帖子:   http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html

最好的做法是始终(总是)始终使用Robert Penner的Signals(而不是自定义事件)和他的NativeSignals(包装所需的原生Flash事件)。

比Flash的原生事件快五倍。 使用弱引用始终安全。 每个信号中的任意数量的有效载荷。

在这里获取SWC:   https://github.com/robertpenner/as3-signals

信号旨在解决您遇到的问题。 想象一下,如果您只是调用:

,而不是创建一个数组并管理它以删除所有侦听器
signalBtnClicked.removeAll();

signalBtnClicked.addOnce( function( e : MouseEvent ) : void { /* do stuff */ } );

知道你刚刚创建的闭包一旦被调用就会被立即取消引用,并且很快就会在GC进行巡视时过夜。