美文网首页
避免list的并发修改异常的几种方式

避免list的并发修改异常的几种方式

作者: tinyvampirepudg | 来源:发表于2021-07-13 12:42 被阅读0次

避免list的并发修改异常的几种方式

1、使用list的snapshot,遍历它的副本

使用如下:com.bumptech.glide.manager.ActivityFragmentLifecycle#onStart()

for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
  lifecycleListener.onStart();
}

具体实现如下:
com.bumptech.glide.util.Util:

/**
 * Returns a copy of the given list that is safe to iterate over and perform actions that may
 * modify the original list.
 *
 * <p>See #303, #375, #322, #2262.
 */
@NonNull
@SuppressWarnings("UseBulkOperation")
public static <T> List<T> getSnapshot(@NonNull Collection<T> other) {
  // toArray creates a new ArrayList internally and does not guarantee that the values it contains
  // are non-null. Collections.addAll in ArrayList uses toArray internally and therefore also
  // doesn't guarantee that entries are non-null. WeakHashMap's iterator does avoid returning null
  // and is therefore safe to use. See #322, #2262.
  List<T> result = new ArrayList<>(other.size());
  for (T item : other) {
    if (item != null) {
      result.add(item);
    }
  }
  return result;
}

2、使用CopyOnWriteArrayList

具体可以参考给ViewTreeObserver添加OnGlobalLayoutListener:


// Non-recursive listeners use CopyOnWriteArray
// Any listener invoked from ViewRootImpl.performTraversals() should not be recursive
@UnsupportedAppUsage
private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;


/**
 * Register a callback to be invoked when the global layout state or the visibility of views
 * within the view tree changes
 *
 * @param listener The callback to add
 *
 * @throws IllegalStateException If {@link #isAlive()} returns false
 */
public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
    checkIsAlive();


    if (mOnGlobalLayoutListeners == null) {
        mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
    }


    mOnGlobalLayoutListeners.add(listener);
}

/**
 * Remove a previously installed global layout callback
 *
 * @param victim The callback to remove
 *
 * @throws IllegalStateException If {@link #isAlive()} returns false
 * 
 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
 */
public void removeOnGlobalLayoutListener(OnGlobalLayoutListener victim) {
    checkIsAlive();
    if (mOnGlobalLayoutListeners == null) {
        return;
    }
    mOnGlobalLayoutListeners.remove(victim);
}

/**
 * Notifies registered listeners that a global layout happened. This can be called
 * manually if you are forcing a layout on a View or a hierarchy of Views that are
 * not attached to a Window or in the GONE state.
 */
public final void dispatchOnGlobalLayout() {
    // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
    // perform the dispatching. The iterator is a safe guard against listeners that
    // could mutate the list by calling the various add/remove methods. This prevents
    // the array from being modified while we iterate it.
    final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
    if (listeners != null && listeners.size() > 0) {
        CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
        try {
            int count = access.size();
            for (int i = 0; i < count; i++) {
                access.get(i).onGlobalLayout();
            }
        } finally {
            listeners.end();
        }
    }
}

/**addOnGlobalLayoutListener
 * Register a callback to be invoked when the global layout state or the visibility of views
 * within the view tree changes
 *
 * @param listener The callback to add
 *
 * @throws IllegalStateException If {@link #isAlive()} returns false
 */
public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
    checkIsAlive();


    if (mOnGlobalLayoutListeners == null) {
        mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
    }


    mOnGlobalLayoutListeners.add(listener);
}

/**
 * Notifies registered listeners that a global layout happened. This can be called
 * manually if you are forcing a layout on a View or a hierarchy of Views that are
 * not attached to a Window or in the GONE state.
 */
public final void dispatchOnGlobalLayout() {
    // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
    // perform the dispatching. The iterator is a safe guard against listeners that
    // could mutate the list by calling the various add/remove methods. This prevents
    // the array from being modified while we iterate it.
    final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
    if (listeners != null && listeners.size() > 0) {
        CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
        try {
            int count = access.size();
            for (int i = 0; i < count; i++) {
                access.get(i).onGlobalLayout();
            }
        } finally {
            listeners.end();
        }
    }
}

相关文章

  • 避免list的并发修改异常的几种方式

    避免list的并发修改异常的几种方式 1、使用list的snapshot,遍历它的副本 使用如下:com.bump...

  • 寒假12:List

    List集合的概述和特点 List特有方法 并发修改异常 ListIterator

  • 【Java】【集合框架】集合框架(list)

    集合框架(list) ArrayList(数组集合)查询与修改快 迭代器并发修改异常解决方案 LinkedList...

  • List集合

    List集合特有的方法 list集合可以用迭代器和for循环进行遍历 迭代器并发修改异常 ListIterator...

  • 2020-06-28【List】

    List特有方法 并发修改异常 ListIterator 增强for循环 小练习 数据结构 栈 队列 数组 链表 ...

  • 04.并发修改异常

    并发修改异常 当使用迭代器遍历集合的时候,使用了集合中的 增加/删除 方法,导致并发修改异常产生 并发修改异常解决...

  • 并发修改异常和有趣的倒数第二个元素

    Paragraph one : 什么是并发修改异常? 并发修改异常即ConcurrentModificationE...

  • Java集合(二)

    1. List集合简单使用 2. 并发修改异常产生的原因和处理 3. 简单学习ListIterator(了解反向遍...

  • 并发修改异常

    案例:判断集合中是否存在java,如果有则添加android且遍历集合元素 方法一:使用collection集合中...

  • Java中的Iterable与Iterator详解

    在Java中,我们可以对List集合进行如下几种方式的遍历: List list =newArrayList<>(...

网友评论

      本文标题:避免list的并发修改异常的几种方式

      本文链接:https://www.haomeiwen.com/subject/rczjpltx.html