101: Fix cache issues r=msfjarvis a=Skrilltrax



Co-authored-by: Aditya Wasan <adityawasan55@gmail.com>
This commit is contained in:
bors[bot] 2021-02-05 10:38:39 +00:00 committed by GitHub
commit 147f2d23a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 20 deletions

View file

@ -5,7 +5,7 @@ import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.components.SingletonComponent
import dev.msfjarvis.lobsters.data.api.LobstersApi
import okhttp3.OkHttpClient
import retrofit2.Retrofit
@ -13,7 +13,7 @@ import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.create
@Module
@InstallIn(ViewModelComponent::class)
@InstallIn(SingletonComponent::class)
object ApiModule {
@Provides

View file

@ -1,18 +1,21 @@
package dev.msfjarvis.lobsters.data.remote
import androidx.paging.PagingSource
import dev.msfjarvis.lobsters.data.api.LobstersApi
import dev.msfjarvis.lobsters.data.local.LobstersPost
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
import javax.inject.Inject
class LobstersPagingSource @Inject constructor(
private val lobstersApi: LobstersApi,
private val lobstersRepository: LobstersRepository,
) : PagingSource<Int, LobstersPost>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> {
return try {
val page = params.key ?: 1
val posts = lobstersApi.getHottestPosts(page)
// Update cache before fetching a list.
// This is done to make sure that we can update the isSaved status of incoming posts.
lobstersRepository.updateCache()
val posts = lobstersRepository.fetchPosts(page)
LoadResult.Page(
data = posts,

View file

@ -1,26 +1,21 @@
package dev.msfjarvis.lobsters.data.repo
import dev.msfjarvis.lobsters.data.api.LobstersApi
import dev.msfjarvis.lobsters.data.local.LobstersPost
import dev.msfjarvis.lobsters.database.LobstersDatabase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext
import javax.inject.Inject
class LobstersRepository @Inject constructor(private val lobstersDatabase: LobstersDatabase) {
class LobstersRepository constructor(
private val lobstersApi: LobstersApi,
private val lobstersDatabase: LobstersDatabase,
) {
private val savedPostsCache: MutableMap<String, LobstersPost> = mutableMapOf()
private val coroutineScope = CoroutineScope(Job() + Dispatchers.IO)
init {
coroutineScope.launch {
getAllPosts().forEach {
savedPostsCache.putIfAbsent(it.short_id, it)
}
}
}
private val _isCacheReady = MutableStateFlow(false)
val isCacheReady = _isCacheReady.asStateFlow()
fun isPostSaved(postId: String): Boolean {
return savedPostsCache.containsKey(postId)
@ -34,6 +29,20 @@ class LobstersRepository @Inject constructor(private val lobstersDatabase: Lobst
return savedPostsCache.values.toList()
}
suspend fun fetchPosts(page: Int): List<LobstersPost> = withContext(Dispatchers.IO) {
return@withContext lobstersApi.getHottestPosts(page)
}
suspend fun updateCache() {
if (_isCacheReady.value) return
val posts = getAllPosts()
posts.forEach {
savedPostsCache[it.short_id] = it
}
_isCacheReady.value = true
}
private suspend fun getPost(postId: String): LobstersPost? = withContext(Dispatchers.IO) {
return@withContext lobstersDatabase.postQueries.selectPost(postId).executeAsOneOrNull()
}

View file

@ -0,0 +1,24 @@
package dev.msfjarvis.lobsters.injection
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dev.msfjarvis.lobsters.data.api.LobstersApi
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
import dev.msfjarvis.lobsters.database.LobstersDatabase
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {
@Singleton
@Provides
fun provideLobstersRepository(
lobstersApi: LobstersApi,
lobstersDatabase: LobstersDatabase
): LobstersRepository {
return LobstersRepository(lobstersApi, lobstersDatabase)
}
}

View file

@ -11,6 +11,8 @@ import dev.msfjarvis.lobsters.data.remote.LobstersPagingSource
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -19,12 +21,20 @@ class LobstersViewModel @Inject constructor(
private val lobstersRepository: LobstersRepository,
private val pagingSource: LobstersPagingSource,
) : ViewModel() {
private val _savedPosts = MutableStateFlow(lobstersRepository.getAllPostsFromCache())
private val _savedPosts = MutableStateFlow<List<LobstersPost>>(emptyList())
val savedPosts = _savedPosts.asStateFlow()
val posts = Pager(PagingConfig(25)) {
pagingSource
}.flow.cachedIn(viewModelScope)
init {
lobstersRepository.isCacheReady.onEach { ready ->
if (ready) {
_savedPosts.value = lobstersRepository.getAllPostsFromCache()
}
}.launchIn(viewModelScope)
}
fun toggleSave(post: LobstersPost) {
viewModelScope.launch {
val isSaved = lobstersRepository.isPostSaved(post.short_id)