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) }
}