refactor(android): switch to DispatcherProvider

This commit is contained in:
Harsh Shandilya 2022-09-09 12:02:22 +05:30
parent 1db2f3256d
commit 59b35a9255
No known key found for this signature in database
5 changed files with 61 additions and 13 deletions

View file

@ -41,6 +41,7 @@ dependencies {
kapt(libs.dagger.hilt.compiler) kapt(libs.dagger.hilt.compiler)
implementation(projects.api) implementation(projects.api)
implementation(projects.common) implementation(projects.common)
implementation(projects.coroutineUtils)
implementation(projects.database) implementation(projects.database)
implementation(projects.metadataExtractor) implementation(projects.metadataExtractor)
implementation(projects.model) implementation(projects.model)

View file

@ -0,0 +1,41 @@
package dev.msfjarvis.claw.android.injection
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dev.msfjarvis.claw.util.coroutines.DefaultDispatcherProvider
import dev.msfjarvis.claw.util.coroutines.DispatcherProvider
import javax.inject.Qualifier
import kotlinx.coroutines.CoroutineDispatcher
@Module
@InstallIn(SingletonComponent::class)
abstract class CoroutineDispatcherModule {
@Binds abstract fun DefaultDispatcherProvider.bind(): DispatcherProvider
companion object {
@[Provides IODispatcher]
fun provideIODispatcher(dispatcherProvider: DispatcherProvider): CoroutineDispatcher {
return dispatcherProvider.io()
}
@[Provides DatabaseDispatcher]
fun provideDatabaseDispatcher(dispatcherProvider: DispatcherProvider): CoroutineDispatcher {
return dispatcherProvider.database()
}
@[Provides MainDispatcher]
fun provideMainDispatcher(dispatcherProvider: DispatcherProvider): CoroutineDispatcher {
return dispatcherProvider.main()
}
}
}
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DatabaseDispatcher
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class MainDispatcher
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class IODispatcher

View file

@ -3,17 +3,18 @@ package dev.msfjarvis.claw.android.paging
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.paging.PagingState import androidx.paging.PagingState
import dev.msfjarvis.claw.model.LobstersPost import dev.msfjarvis.claw.model.LobstersPost
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
class LobstersPagingSource( class LobstersPagingSource(
private val getMorePosts: suspend (Int) -> List<LobstersPost>, private val getMorePosts: suspend (Int) -> List<LobstersPost>,
private val ioDispatcher: CoroutineDispatcher,
) : PagingSource<Int, LobstersPost>() { ) : PagingSource<Int, LobstersPost>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> { override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> {
return try { return try {
val page = params.key ?: 1 val page = params.key ?: 1
val posts = withContext(Dispatchers.IO) { getMorePosts(page) } val posts = withContext(ioDispatcher) { getMorePosts(page) }
LoadResult.Page( LoadResult.Page(
data = posts, data = posts,

View file

@ -5,12 +5,13 @@ import androidx.lifecycle.viewModelScope
import androidx.paging.Pager import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dev.msfjarvis.claw.android.injection.IODispatcher
import dev.msfjarvis.claw.android.paging.LobstersPagingSource import dev.msfjarvis.claw.android.paging.LobstersPagingSource
import dev.msfjarvis.claw.android.ui.toLocalDateTime import dev.msfjarvis.claw.android.ui.toLocalDateTime
import dev.msfjarvis.claw.api.LobstersApi import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.database.local.SavedPost import dev.msfjarvis.claw.database.local.SavedPost
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -24,16 +25,19 @@ constructor(
private val api: LobstersApi, private val api: LobstersApi,
private val savedPostsRepository: SavedPostsRepository, private val savedPostsRepository: SavedPostsRepository,
private val postDetailsRepository: PostDetailsRepository, private val postDetailsRepository: PostDetailsRepository,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
) : ViewModel() { ) : ViewModel() {
private var hottestPostsPagingSource: LobstersPagingSource? = null private var hottestPostsPagingSource: LobstersPagingSource? = null
private var newestPostsPagingSource: LobstersPagingSource? = null private var newestPostsPagingSource: LobstersPagingSource? = null
private val hottestPostsPager = private val hottestPostsPager =
Pager(PagingConfig(20)) { Pager(PagingConfig(20)) {
LobstersPagingSource(api::getHottestPosts).also { hottestPostsPagingSource = it } LobstersPagingSource(api::getHottestPosts, ioDispatcher).also {
hottestPostsPagingSource = it
}
} }
private val newestPostsPager = private val newestPostsPager =
Pager(PagingConfig(20)) { Pager(PagingConfig(20)) {
LobstersPagingSource(api::getNewestPosts).also { newestPostsPagingSource = it } LobstersPagingSource(api::getNewestPosts, ioDispatcher).also { newestPostsPagingSource = it }
} }
val hottestPosts val hottestPosts
@ -58,7 +62,7 @@ constructor(
} }
fun toggleSave(post: SavedPost) { fun toggleSave(post: SavedPost) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(ioDispatcher) {
val saved = isPostSaved(post) val saved = isPostSaved(post)
if (saved) { if (saved) {
savedPostsRepository.removePost(post) savedPostsRepository.removePost(post)
@ -69,14 +73,13 @@ constructor(
} }
suspend fun getPostComments(postId: String) = suspend fun getPostComments(postId: String) =
withContext(Dispatchers.IO) { withContext(ioDispatcher) {
val details = api.getPostDetails(postId) val details = api.getPostDetails(postId)
val extendedDetails = postDetailsRepository.getExtendedDetails(details) val extendedDetails = postDetailsRepository.getExtendedDetails(details)
extendedDetails extendedDetails
} }
suspend fun getUserProfile(username: String) = suspend fun getUserProfile(username: String) = withContext(ioDispatcher) { api.getUser(username) }
withContext(Dispatchers.IO) { api.getUser(username) }
fun refreshHottestPosts() { fun refreshHottestPosts() {
hottestPostsPagingSource?.invalidate() hottestPostsPagingSource?.invalidate()

View file

@ -2,29 +2,31 @@ package dev.msfjarvis.claw.android.viewmodel
import app.cash.sqldelight.coroutines.asFlow import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList import app.cash.sqldelight.coroutines.mapToList
import dev.msfjarvis.claw.android.injection.DatabaseDispatcher
import dev.msfjarvis.claw.database.LobstersDatabase import dev.msfjarvis.claw.database.LobstersDatabase
import dev.msfjarvis.claw.database.local.SavedPost import dev.msfjarvis.claw.database.local.SavedPost
import io.github.aakira.napier.Napier import io.github.aakira.napier.Napier
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
class SavedPostsRepository class SavedPostsRepository
@Inject @Inject
constructor( constructor(
database: LobstersDatabase, database: LobstersDatabase,
@DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher,
) { ) {
private val savedPostQueries = database.savedPostQueries private val savedPostQueries = database.savedPostQueries
val savedPosts = savedPostQueries.selectAllPosts().asFlow().mapToList() val savedPosts = savedPostQueries.selectAllPosts().asFlow().mapToList(dbDispatcher)
suspend fun savePost(post: SavedPost) { suspend fun savePost(post: SavedPost) {
Napier.d(tag = TAG) { "Saving post: ${post.shortId}" } Napier.d(tag = TAG) { "Saving post: ${post.shortId}" }
withContext(Dispatchers.IO) { savedPostQueries.insertOrReplacePost(post) } withContext(dbDispatcher) { savedPostQueries.insertOrReplacePost(post) }
} }
suspend fun removePost(post: SavedPost) { suspend fun removePost(post: SavedPost) {
Napier.d(tag = TAG) { "Removing post: ${post.shortId}" } Napier.d(tag = TAG) { "Removing post: ${post.shortId}" }
withContext(Dispatchers.IO) { savedPostQueries.deletePost(post.shortId) } withContext(dbDispatcher) { savedPostQueries.deletePost(post.shortId) }
} }
private companion object { private companion object {