2010-07-20 46 views
1

我想弄清楚使用匿名事件偵聽器的最佳選擇,使用後100%垃圾收集。我得到了這兩個例子,但我想知道如果它實際上使它們之間有什麼區別?匿名事件偵聽器有什麼更好的選擇?

var listener1:Function = function(e:Event):void 
{ 
resource.removeEventListener(e.type, listener1); 
loadedHandler(resource); 
listener1 = null; 
}; 
resource.addEventListener(ResourceEvent.LOADED, listener1); 

或這一個...

resource.addEventListener(ResourceEvent.LOADED, function(e:Event):void 
{ 
Resource(e.currentTarget).removeEventListener(e.type, arguments["callee"]); 
loadedHandler(resource); 

}, false, 0, true); 

還是會有任何其他更好的解決方案?這對我來說非常重要,因爲這些偵聽器和函數可能會在應用程序中經常執行,所以這些偵聽器和函數會從內存中正確刪除。我可以去使用一個Dictionary來映射所有的監聽器等,然後在非匿名監聽器等中測試並刪除它們,但是這會很快涉及到,因爲可能會出現資源可以同時異步加載的情況在應用程序的不同類。


@dominic: 你的意思是將這樣的功能添加到方法中,對不對?正如我上面寫的應用程序加載資源異步,可能會發生,當前正在加載資源,而應用程序中其他地方的另一個類請求相同的資源。資源管理類(其中的代碼是)然後掛鉤到由資源調度的事件監聽器。據我瞭解,如果我在你的例子中使用類方法或函數作爲監聽器,它們將被新請求重新使用,並且舊請求的事件將永遠不會觸發。因此匿名函數存儲在一個變量中。我假設他們都留在內存中,直到他們各自的請求完成。 但也許我完全混淆了這一點,情況並非如此?我有時會發現事件很難掌握。

回答

1

事件處理函數/方法在這裏並不是真正的問題。

如果我明白你說的是,你有一個ResourceManager類,當你的應用程序中的類需要這樣做時,它會加載某個資源。當資源被完全加載,資源調度,將觸發事件處理程序的事件:

resource.addEventListener(ResourceEvent.LOADED, listener1); 

所以現在listener1函數或方法將被調用。 問題是,如果在listener1中您決定刪除事件監聽器,那麼現在進一步加載資源完成將觸發監聽器1處理程序,因爲管理器不再監聽它。 如果應用程序中的兩個不同類同時加載資源,則將爲每個ResourceEvent.LOADED事件調用一次listener1處理程序。

在我看來,你應該離開事件監聽器,並且只有在所有資源都被加載後纔將其刪除,並使用管理器來控制對資源加載的訪問,以便它是集中的,並且所有ResourceEvent.LOADED事件將由listener1函數/方法處理。 然後,如果您的應用程序在其整個生命週期中加載資源,請不要刪除該偵聽器,只在您不再需要時刪除它。

我不是100%確定我明白你的意思,所以我希望我在這裏不是主題! 希望這有助於。

+0

)感謝您的幫助!是的,它與您描述的類似,資源管理器處理加載(和卸載)的資源,但是沒有可預期的情況,所有的資源都被加載,如果任何類需要它們,RM會根據需要加載資源,如果不再需要它們,它們也可以被卸載(並且隨後再次被重新加載等)所以沒有必要說可以安全地說所有的資源都被加載了。 – BadmintonCat 2010-07-20 17:43:34

+0

在這種情況下,您不應該刪除事件處理程序,否則您將無法迴應ResourceEvent.LOADED事件 – dotminic 2010-07-20 18:02:02

+0

但問題是許多資源對象是在RM中創建的,因此不會重新使用即使他們不再需要它們,他們也將永遠擁有事件監聽器。 – BadmintonCat 2010-07-20 18:35:19

2

第一個看起來更清晰,並且避免使用強制轉換和數組查找來刪除偵聽器。 你爲什麼使用「匿名」處理函數? 您可以像這樣使用它,它更清潔一點,這就是asdocs建議使用事件模型的方式。

function listener1(e:ResourceEvent):void 
{ 
    resource.removeEventListener(e.type, listener1); 
    loadedHandler(resource); 
}; 
resource.addEventListener(ResourceEvent.LOADED, listener1); 
+0

請看我上面的回覆(評論表不允許我發送那麼多文本!:( – BadmintonCat 2010-07-20 15:34:43

2

這不回答你「與」直接的問題,但我即將發佈名爲raix的.NET框架Reactive Extensions的AS3端口,解決問題就像這樣:

Observable.fromEvent(resource, ResourceEvent.LOADED) 
    .take(1) 
    .subscribe(function(e : ResourceEvent) : void 
    { 
     // just the subscriber code 
    }); 

的使用take表示它將在第一個事件後自動取消訂閱。如果您不喜歡匿名函數,也可以手動訂閱對方法的引用,而不必擔心以後再刪除它。

雖然這不是有意的,但請讓我知道,如果這個答案太「垃圾」,我會刪除它。

0

在這種情況下,我認爲在使用匿名偵聽器方面沒有任何優勢(儘管在其他一些情況下可能更乾淨,但我認爲您在這裏沒有任何收穫)。

不管怎樣,有幾件事情需要注意:

1)你的第二個選項是自找麻煩。不要使用弱引用來匿名函數。您的聽衆可以在事件派發之前收集。 (我認爲不要使用弱引用時期,但在大多數情況下是相當個人的品味;但在這種情況下,它不是)。

2)只要您確定監聽器總是會啓動並且這是唯一的事件將被調度,這種方法就會工作。如果您的調度員觸發某個事件來發出錯誤信號,您的聽衆將不會被刪除。

3)刪除監聽器不一定與垃圾收集有關。在某些情況下,不刪除監聽器會導致泄漏(例如,在舞臺上聆聽時)。但是,在大多數情況下,不刪除監聽器不會導致泄漏(即使使用強引用也是如此)。我知道你可能想刪除聽衆,因爲你不再想聽某個事件,這是正確的,但我只是想補充一點。

0

謝謝你的提示!我現在通過創建一個簡單的映射來解決負載和失敗處理程序由資源ID映射的問題。這裏的基本思想是:

這將替換我的原代碼:

private var _listeners:Object = {}; 

public function load(resourceID:String):void 
{ 
    ... 

    if (loadedHandler != null || failedHandler != null) 
    { 
     _listeners[resource.id] = new ListenerVO(loadedHandler, failedHandler); 
     if (loadedHandler != null) 
     { 
      resource.addEventListener(ResourceEvent.LOADED, onResourceProcessed); 
     } 
     if (failedHandler != null) 
     { 
      resource.addEventListener(ResourceEvent.FAILED, onResourceProcessed); 
     } 
    } 

    ... 
} 

這裏有新的事件處理程序:

private function onResourceProcessed(e:ResourceEvent):void 
{ 
    var r:Resource = e.resource; 
    var handler:Function; 
    r.removeEventListener(e.type, onResourceProcessed); 

    if (e.type == ResourceEvent.LOADED) 
     handler = ListenerVO(_listeners[r.id]).loadedHandler; 
    else if (e.type == ResourceEvent.FAILED) 
     handler = ListenerVO(_listeners[r.id]).failedHandler; 

    if (handler != null) 
    { 
     _listeners[r.id] = null; 
     delete _listeners[r.id]; 
     handler(r); 
    } 
} 

,封裝小級別VO保持它的所有強類型。 ...

class ListenerVO 
{ 
    public var loadedHandler:Function; 
    public var failedHandler:Function; 

    public function ListenerVO(lh:Function, fh:Function) 
    { 
     loadedHandler = lh; 
     failedHandler = fh; 
    } 
} 

讓我知道你對這個想法的看法!