簡體   English   中英

迭代事件處理程序集合時,如何安全地從*回調中刪除處理程序?

[英]While iterating over a collection of event handlers, how do you safely remove a handler from *within* a callback?

我對某事感到有些困惑。 Java的文檔告訴我們在使用Iterator對象迭代該集合時從集合中刪除項目時沒有定義的行為,唯一安全的方法是使用Iterator.remove()。

那么,如果在迭代列表的過程中,其中一個處理程序決定將它自己作為監聽器刪除的話,你會如何安全地從ArrayList中刪除一個事件處理程序?

// in public class Dispatcher

public void dispatchEvent(){
    Iterator<IEventHandler> iterator = mHandlers.iterator();
    IEventHandler handler = null;
    while(iterator.hasNext()){
        handler = iterator.next();
        handler.onCallbackEvent();
    }
}

public void insertHandler(IEventHandler h){
    mHandlers.add(h);
}

public void removeHandler(IEventHandler h){
    mHandlers.remove(h);
}

同時,處理程序像這樣被實例化......

final Dispatcher d = new Dispatcher();
d.insertHandler(new IEventHandler(){
    @Override
    public void onCallbackEvent(){
        Log.i(" callback happened ");
        d.removeHandler(this);
    }
});

看到潛在的問題? 您正在使用Iterator進行迭代時 ,由於在該特定處理程序中聲明的onCallbackEvent() 從ArrayList中刪除處理程序。

這是一個棘手的問題嗎? 處理這種情況的安全方法是什么?

這是實現事件系統時非常常見的問題。 唯一的解決方案是在更改時復制處理程序列表。 您可以在insertHandler / removeHandler方法中自己執行此操作,或者只使用CopyOnWriteArrayList。

您可以重新實現removeHandler來存儲計划刪除的處理程序。

public void removeHandler(IEventHandler h){
    mHandlersToRemove.add(h);
}

然后在進行任何調度之前將其刪除。

public void dispatchEvent(){
    mHandlers.removeAll(mHandlersToRemove);
    mHandlersToRemove.clear();
    ...

您也可以刪除在年底dispatchEvent ,但你只能從處理程序移除。 (否則您可能會分派給已刪除的處理程序。)


如果您對此問題的理論解決方案感興趣,可以查看C ++如何實現迭代器。 在stl向量中,迭代器有一個擦除方法 ,它返回下一個有效的迭代器。

它看起來像這樣:

for (itr = listA.begin(); itr != listA.end(); )
{
    if ( shouldRemove(*itr) ) {
        itr = listA.erase(itr);
    }
    else {
      ++itr;
    }
}

當然,這個例子不適用於你的問題,因為它都是在C ++中,將新迭代器傳播到頂級循環(或者為你的調用添加一個返回值以獲得“刪除”條件)會很尷尬。 但也許在某處有一個類似的java實現:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM