Replace PagingSource factory with Google's impl
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
package gq.kirmanak.mealient.data.recipes
|
||||
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.InvalidatingPagingSourceFactory
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
||||
@@ -12,6 +14,7 @@ import gq.kirmanak.mealient.data.recipes.impl.RecipeRepoImpl
|
||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSourceImpl
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ExperimentalPagingApi
|
||||
@ExperimentalSerializationApi
|
||||
@@ -29,4 +32,12 @@ interface RecipeModule {
|
||||
|
||||
@Binds
|
||||
fun provideRecipeImageLoader(recipeImageLoaderImpl: RecipeImageLoaderImpl): RecipeImageLoader
|
||||
|
||||
companion object {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideRecipePagingSourceFactory(
|
||||
recipeStorage: RecipeStorage
|
||||
) = InvalidatingPagingSourceFactory { recipeStorage.queryRecipes() }
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package gq.kirmanak.mealient.data.recipes.impl
|
||||
|
||||
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
|
||||
|
||||
@Singleton
|
||||
class RecipePagingSourceFactory @Inject constructor(
|
||||
private val recipeStorage: RecipeStorage
|
||||
) : () -> PagingSource<Int, RecipeSummaryEntity> {
|
||||
private val sources: MutableSet<PagingSource<Int, RecipeSummaryEntity>> =
|
||||
ConcurrentSkipListSet(PagingSourceComparator)
|
||||
|
||||
override fun invoke(): PagingSource<Int, RecipeSummaryEntity> {
|
||||
Timber.v("invoke() called")
|
||||
val newSource = recipeStorage.queryRecipes()
|
||||
sources.add(newSource)
|
||||
return newSource
|
||||
}
|
||||
|
||||
fun invalidate() {
|
||||
Timber.v("invalidate() called")
|
||||
for (source in sources) {
|
||||
if (!source.invalid) {
|
||||
source.invalidate()
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package gq.kirmanak.mealient.data.recipes.impl
|
||||
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.InvalidatingPagingSourceFactory
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||
@@ -15,7 +16,7 @@ import javax.inject.Inject
|
||||
class RecipeRepoImpl @Inject constructor(
|
||||
private val mediator: RecipesRemoteMediator,
|
||||
private val storage: RecipeStorage,
|
||||
private val pagingSourceFactory: RecipePagingSourceFactory,
|
||||
private val pagingSourceFactory: InvalidatingPagingSourceFactory<Int, RecipeSummaryEntity>,
|
||||
private val dataSource: RecipeDataSource,
|
||||
) : RecipeRepo {
|
||||
override fun createPager(): Pager<Int, RecipeSummaryEntity> {
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package gq.kirmanak.mealient.data.recipes.impl
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.LoadType
|
||||
import androidx.paging.*
|
||||
import androidx.paging.LoadType.PREPEND
|
||||
import androidx.paging.LoadType.REFRESH
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.RemoteMediator
|
||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
||||
import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
|
||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||
@@ -18,7 +15,7 @@ import javax.inject.Inject
|
||||
class RecipesRemoteMediator @Inject constructor(
|
||||
private val storage: RecipeStorage,
|
||||
private val network: RecipeDataSource,
|
||||
private val pagingSourceFactory: RecipePagingSourceFactory,
|
||||
private val pagingSourceFactory: InvalidatingPagingSourceFactory<Int, RecipeSummaryEntity>,
|
||||
) : RemoteMediator<Int, RecipeSummaryEntity>() {
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package gq.kirmanak.mealient.data.recipes.impl
|
||||
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
||||
import gq.kirmanak.mealient.test.HiltRobolectricTest
|
||||
import kotlinx.coroutines.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import javax.inject.Inject
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
@HiltAndroidTest
|
||||
class RecipePagingSourceFactoryTest : HiltRobolectricTest() {
|
||||
@Inject
|
||||
lateinit var storage: RecipeStorage
|
||||
lateinit var subject: RecipePagingSourceFactory
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
subject = RecipePagingSourceFactory(storage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when modifying concurrently then doesn't throw`(): Unit = runBlocking {
|
||||
(0..100).map {
|
||||
async(Dispatchers.Default) {
|
||||
for (i in 0..100) {
|
||||
subject.invalidate()
|
||||
subject.invoke()
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user