繁体   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