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

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

View File

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

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