Replace PagingSource factory with Google's impl
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes
|
package gq.kirmanak.mealient.data.recipes
|
||||||
|
|
||||||
import androidx.paging.ExperimentalPagingApi
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.InvalidatingPagingSourceFactory
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
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.RecipeDataSource
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSourceImpl
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSourceImpl
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ExperimentalPagingApi
|
@ExperimentalPagingApi
|
||||||
@ExperimentalSerializationApi
|
@ExperimentalSerializationApi
|
||||||
@@ -29,4 +32,12 @@ interface RecipeModule {
|
|||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
fun provideRecipeImageLoader(recipeImageLoaderImpl: RecipeImageLoaderImpl): RecipeImageLoader
|
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
|
package gq.kirmanak.mealient.data.recipes.impl
|
||||||
|
|
||||||
import androidx.paging.ExperimentalPagingApi
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.InvalidatingPagingSourceFactory
|
||||||
import androidx.paging.Pager
|
import androidx.paging.Pager
|
||||||
import androidx.paging.PagingConfig
|
import androidx.paging.PagingConfig
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
@@ -15,7 +16,7 @@ import javax.inject.Inject
|
|||||||
class RecipeRepoImpl @Inject constructor(
|
class RecipeRepoImpl @Inject constructor(
|
||||||
private val mediator: RecipesRemoteMediator,
|
private val mediator: RecipesRemoteMediator,
|
||||||
private val storage: RecipeStorage,
|
private val storage: RecipeStorage,
|
||||||
private val pagingSourceFactory: RecipePagingSourceFactory,
|
private val pagingSourceFactory: InvalidatingPagingSourceFactory<Int, RecipeSummaryEntity>,
|
||||||
private val dataSource: RecipeDataSource,
|
private val dataSource: RecipeDataSource,
|
||||||
) : RecipeRepo {
|
) : RecipeRepo {
|
||||||
override fun createPager(): Pager<Int, RecipeSummaryEntity> {
|
override fun createPager(): Pager<Int, RecipeSummaryEntity> {
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.impl
|
package gq.kirmanak.mealient.data.recipes.impl
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.paging.ExperimentalPagingApi
|
import androidx.paging.*
|
||||||
import androidx.paging.LoadType
|
|
||||||
import androidx.paging.LoadType.PREPEND
|
import androidx.paging.LoadType.PREPEND
|
||||||
import androidx.paging.LoadType.REFRESH
|
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.RecipeStorage
|
||||||
import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.data.recipes.db.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||||
@@ -18,7 +15,7 @@ import javax.inject.Inject
|
|||||||
class RecipesRemoteMediator @Inject constructor(
|
class RecipesRemoteMediator @Inject constructor(
|
||||||
private val storage: RecipeStorage,
|
private val storage: RecipeStorage,
|
||||||
private val network: RecipeDataSource,
|
private val network: RecipeDataSource,
|
||||||
private val pagingSourceFactory: RecipePagingSourceFactory,
|
private val pagingSourceFactory: InvalidatingPagingSourceFactory<Int, RecipeSummaryEntity>,
|
||||||
) : RemoteMediator<Int, RecipeSummaryEntity>() {
|
) : RemoteMediator<Int, RecipeSummaryEntity>() {
|
||||||
|
|
||||||
@VisibleForTesting
|
@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