'Processing list in Coroutines scope causes exception
I have a function that show markers (I call it tasks) on Google Maps. To make it cleaner, I chose an approach that iterates through the already displayed tasks and the new tasks. If a task already exists in maps and does not in the new list, I delete its marker. If the task is in both lists but its version has changed, I modify its marker . And if the task is only in the new list, i add its marker. Each time the user scrolls through the maps, I search for tasks based on the scrolled positon. The user can scroll multiple times, which should stop the previous call of the function.
the problem is that sometimes i get this exception
Fatal Exception: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at com.weryou.android.ui.missions.search.map.SearchMissionMapFragment$displayMissions$1.invokeSuspend(SearchMissionMapFragment.kt:435)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
And this exception
Fatal Exception: java.lang.IndexOutOfBoundsException: Index: 132, Size: 132
at java.util.ArrayList.get(ArrayList.java:437)
at kotlin.collections.CollectionsKt__MutableCollectionsKt.filterInPlace$CollectionsKt__MutableCollectionsKt(CollectionsKt__MutableCollectionsKt.java:284)
at kotlin.collections.CollectionsKt__MutableCollectionsKt.removeAll(CollectionsKt__MutableCollectionsKt.java:269)
at com.weryou.android.ui.missions.search.map.SearchMissionMapFragment$displayMissions$1.invokeSuspend(SearchMissionMapFragment.kt:220)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
This is my function
private val alreadyDisplayedMissions = ArrayList<Pair<MissionHeaderEntity, Marker>>()
private fun displayMissions(newMissions : List<MissionHeaderEntity>)
{
lifecycleScope.launch(Dispatchers.Default) {
val missionsToRemove : List<Pair<MissionHeaderEntity, Marker>> = alreadyDisplayedMissions.filter { oldMission ->
val newVersionOfOldMission : MissionHeaderEntity? = newMissions.find { it.id == oldMission.first.id }
newVersionOfOldMission == null || newVersionOfOldMission != oldMission.first
}
alreadyDisplayedMissions.removeAll { mission -> missionsToRemove.any { mission.first.id == it.first.id } }
// Loop in the new missions to display in map all new missions with a determined location,
// plus the tuto mission of the user if exists.
val missionsToShow : List<Pair<MissionHeaderEntity, MarkerOptions>> = newMissions.filter { newMission ->
(newMission.firstMission == true && newMission.owned == true)
|| alreadyDisplayedMissions.none { newMission.id == it.first.id }
|| (newMission.place?.address?.location?.latitude != null && newMission.place?.address?.location?.longitude != null)
}.map { newMission ->
// The icon resource of the marker to display
val markerIcon : Drawable = when(newMission.state)
{
MissionState.BOOKED -> markerMissionBooked
MissionState.AVAILABLE -> markerMissionAvailable
MissionState.PRE_RELEASED -> markerMissionPreReleased
else -> markerMissionOwned
}
// The icon of the marker to display .
val markerBitmap : Bitmap = mapUtils.createMissionMarkerIcon(markerIcon, newMission.costing?.price.toCurrency(requireContext()))
val markerLatitude : Double = newMission.place?.address?.location?.latitude!!
val markerLongitude : Double = newMission.place?.address?.location?.longitude!!
// The location of the marker to display.
val markerLatLng = LatLng(markerLatitude, markerLongitude)
val markerOptions : MarkerOptions = MarkerOptions()
.position(markerLatLng)
.icon(BitmapDescriptorFactory.fromBitmap(markerBitmap))
Pair(newMission, markerOptions)
}
lifecycleScope.launch(Dispatchers.Main) {
missionsToRemove.forEach { it.second.remove() }
missionsToShow.forEach {
val marker : Marker? = googleMap?.addMarker(it.second)
marker?.tag = it.first
alreadyDisplayedMissions.add(Pair(it.first, marker!!))
}
}
}
}
What's wrong in my function and how to solve those exceptions?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
