Replace PagingSource factory with Google's impl

This commit is contained in:
Kirill Kamakin
2021-11-26 19:39:28 +03:00
parent 20c3fa8e20
commit 91078de1a7
5 changed files with 15 additions and 86 deletions

View File

@@ -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() }
}
}

View File

@@ -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
}
}
}

View File

@@ -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> {

View File

@@ -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

View File

@@ -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()
}
}