Fix ConcurrentModificationException

This commit is contained in:
Benoit Marty 2019-06-20 17:03:14 +02:00
parent 3e97503220
commit 401f878a9c

View File

@ -88,34 +88,37 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,


private val listUpdateCallback = object : ListUpdateCallback { private val listUpdateCallback = object : ListUpdateCallback {


@Synchronized
override fun onChanged(position: Int, count: Int, payload: Any?) { override fun onChanged(position: Int, count: Int, payload: Any?) {
synchronized(modelCache) {
assertUpdateCallbacksAllowed() assertUpdateCallbacksAllowed()
(position until (position + count)).forEach { (position until (position + count)).forEach {
modelCache[it] = null modelCache[it] = null
} }
requestModelBuild() requestModelBuild()
} }
}


@Synchronized
override fun onMoved(fromPosition: Int, toPosition: Int) { override fun onMoved(fromPosition: Int, toPosition: Int) {
synchronized(modelCache) {
assertUpdateCallbacksAllowed() assertUpdateCallbacksAllowed()
val model = modelCache.removeAt(fromPosition) val model = modelCache.removeAt(fromPosition)
modelCache.add(toPosition, model) modelCache.add(toPosition, model)
requestModelBuild() requestModelBuild()
} }
}


@Synchronized
override fun onInserted(position: Int, count: Int) { override fun onInserted(position: Int, count: Int) {
synchronized(modelCache) {
assertUpdateCallbacksAllowed() assertUpdateCallbacksAllowed()
(0 until count).forEach { (0 until count).forEach {
modelCache.add(position, null) modelCache.add(position, null)
} }
requestModelBuild() requestModelBuild()
} }
}


@Synchronized
override fun onRemoved(position: Int, count: Int) { override fun onRemoved(position: Int, count: Int) {
synchronized(modelCache) {
assertUpdateCallbacksAllowed() assertUpdateCallbacksAllowed()
(0 until count).forEach { (0 until count).forEach {
modelCache.removeAt(position) modelCache.removeAt(position)
@ -123,6 +126,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
requestModelBuild() requestModelBuild()
} }
} }
}


init { init {
requestModelBuild() requestModelBuild()
@ -134,19 +138,23 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
this.timeline?.listener = this this.timeline?.listener = this


// Clear cache // Clear cache
synchronized(modelCache) {
for (i in 0 until modelCache.size) { for (i in 0 until modelCache.size) {
modelCache[i] = null modelCache[i] = null
} }
} }
}


if (this.eventIdToHighlight != eventIdToHighlight) { if (this.eventIdToHighlight != eventIdToHighlight) {
// Clear cache to force a refresh // Clear cache to force a refresh
synchronized(modelCache) {
for (i in 0 until modelCache.size) { for (i in 0 until modelCache.size) {
if (modelCache[i]?.eventId == eventIdToHighlight if (modelCache[i]?.eventId == eventIdToHighlight
|| modelCache[i]?.eventId == this.eventIdToHighlight) { || modelCache[i]?.eventId == this.eventIdToHighlight) {
modelCache[i] = null modelCache[i] = null
} }
} }
}
this.eventIdToHighlight = eventIdToHighlight this.eventIdToHighlight = eventIdToHighlight


requestModelBuild() requestModelBuild()
@ -194,8 +202,8 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
require(inSubmitList || Looper.myLooper() == backgroundHandler.looper) require(inSubmitList || Looper.myLooper() == backgroundHandler.looper)
} }


@Synchronized
private fun getModels(): List<EpoxyModel<*>> { private fun getModels(): List<EpoxyModel<*>> {
synchronized(modelCache) {
(0 until modelCache.size).forEach { position -> (0 until modelCache.size).forEach { position ->
// Should be build if not cached or if cached but contains mergedHeader or formattedDay // Should be build if not cached or if cached but contains mergedHeader or formattedDay
// We then are sure we always have items up to date. // We then are sure we always have items up to date.
@ -217,6 +225,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
.flatten() .flatten()
.filterNotNull() .filterNotNull()
} }
}




private fun buildItemModels(currentPosition: Int, items: List<TimelineEvent>): CacheItemData { private fun buildItemModels(currentPosition: Int, items: List<TimelineEvent>): CacheItemData {
@ -296,6 +305,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
} }


fun searchPositionOfEvent(eventId: String): Int? { fun searchPositionOfEvent(eventId: String): Int? {
synchronized(modelCache) {
// Search in the cache // Search in the cache
modelCache.forEachIndexed { idx, cacheItemData -> modelCache.forEachIndexed { idx, cacheItemData ->
if (cacheItemData?.eventId == eventId) { if (cacheItemData?.eventId == eventId) {
@ -305,7 +315,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,


return null return null
} }

}
} }


private data class CacheItemData( private data class CacheItemData(