Meika
03/16/2023, 6:26 PMConcurrentModificationException when iterating (and modify) a mutable list. detail in thread 🧵Meika
03/16/2023, 6:26 PMforEach iteration. am I missing something here? snippet of the relevant code:
class Bindable<T>() {
private val bindings: WeakReferenceList<Bindable<T>> = mutableWeakListOf()
fun unbindFrom(bindable: Bindable<T>) {
removeBinding(bindable.weakReference)
bindable.removeBinding(weakReference)
}
private fun removeBinding(ref: WeakReference<Bindable<T>>) {
bindings.remove(ref)
}
fun unbindBindings() {
if (bindings.isNotEmpty()) {
bindings.forAliveRefs { it.unbindFrom(this) }
bindings.clear()
}
}
}
internal class WeakReferenceList<T>(private val delegate: MutableList<WeakReference<T>>) :
MutableList<WeakReference<T>> by delegate {
override fun contains(element: WeakReference<T>): Boolean = synchronized(this) {
return delegate.any { it.get()?.equals(element) ?: false }
}
fun forAliveRefs(clearDestroyedRefs: Boolean = true, action: (T) -> Unit) = synchronized(this) {
if (clearDestroyedRefs) removeDestroyedRefs()
delegate.forEach { it.get()?.let(action) }
}
}
got ConcurrentModificationException on forEach lineMeika
03/16/2023, 6:31 PMiterator but still no luckRiccardo Lippolis
03/16/2023, 6:37 PMMutableList.remove function while iterating the list with forEach, which does indeed cause this exception with certain list implementations (not sure which one you are using here).
Not sure what you mean with your last remark, but when using a Java iterator you can call iterator.remove() which is safe to perform even while iterating.
Alternatively you can use another List implementation that does support concurrent modification, but that might be overkill in this scenario.Meika
03/16/2023, 6:52 PMdelegate.iterator() to iterate the list but the since the remove action are passed as function param so I can't use iterator.remove() .Meika
03/17/2023, 4:56 AMfun getAliveRefs(): List<WeakReference<T>> = synchronized(this) {
delegate.filter { it.get() != null }
}
fun forAliveRefs(action: (T) -> Unit) = synchronized(this) {
getAliveRefs().forEach { it.get()?.let(action) }
}