Fix ConcurrentModificationException in RecipePagingSourceFactory
It seems that it is possible to launch several coroutines on same main thread of application. That's why it is possible to launch both invoke and invalidate at the same time even though they are marked as synchronized. To fix the issue this commit uses a concurrent collection instead of synchronization.
This commit is contained in:
@@ -4,6 +4,7 @@ import androidx.paging.PagingSource
|
||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
||||
import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.ConcurrentSkipListSet
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@@ -11,9 +12,9 @@ import javax.inject.Singleton
|
||||
class RecipePagingSourceFactory @Inject constructor(
|
||||
private val recipeStorage: RecipeStorage
|
||||
) : () -> PagingSource<Int, RecipeSummaryEntity> {
|
||||
private val sources: MutableList<PagingSource<Int, RecipeSummaryEntity>> = mutableListOf()
|
||||
private val sources: MutableSet<PagingSource<Int, RecipeSummaryEntity>> =
|
||||
ConcurrentSkipListSet(PagingSourceComparator)
|
||||
|
||||
@Synchronized
|
||||
override fun invoke(): PagingSource<Int, RecipeSummaryEntity> {
|
||||
Timber.v("invoke() called")
|
||||
val newSource = recipeStorage.queryRecipes()
|
||||
@@ -21,7 +22,6 @@ class RecipePagingSourceFactory @Inject constructor(
|
||||
return newSource
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun invalidate() {
|
||||
Timber.v("invalidate() called")
|
||||
for (source in sources) {
|
||||
@@ -31,4 +31,15 @@ class RecipePagingSourceFactory @Inject constructor(
|
||||
}
|
||||
sources.removeAll { it.invalid }
|
||||
}
|
||||
|
||||
private object PagingSourceComparator : Comparator<PagingSource<Int, RecipeSummaryEntity>> {
|
||||
override fun compare(
|
||||
left: PagingSource<Int, RecipeSummaryEntity>?,
|
||||
right: PagingSource<Int, RecipeSummaryEntity>?
|
||||
): Int {
|
||||
val leftHash = left?.hashCode() ?: 0
|
||||
val rightHash = right?.hashCode() ?: 0
|
||||
return leftHash - rightHash
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user