From 59b35a9255d23bf8d0e637e9259544d181a9cd31 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Fri, 9 Sep 2022 12:02:22 +0530 Subject: [PATCH] refactor(android): switch to DispatcherProvider --- android/build.gradle.kts | 1 + .../injection/CoroutineDispatcherModule.kt | 41 +++++++++++++++++++ .../android/paging/LobstersPagingSource.kt | 5 ++- .../claw/android/viewmodel/ClawViewModel.kt | 17 ++++---- .../android/viewmodel/SavedPostsRepository.kt | 10 +++-- 5 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 android/src/main/kotlin/dev/msfjarvis/claw/android/injection/CoroutineDispatcherModule.kt diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 437e5e90..0f698c9e 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { kapt(libs.dagger.hilt.compiler) implementation(projects.api) implementation(projects.common) + implementation(projects.coroutineUtils) implementation(projects.database) implementation(projects.metadataExtractor) implementation(projects.model) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/injection/CoroutineDispatcherModule.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/injection/CoroutineDispatcherModule.kt new file mode 100644 index 00000000..380b5f7d --- /dev/null +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/injection/CoroutineDispatcherModule.kt @@ -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 diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/LobstersPagingSource.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/LobstersPagingSource.kt index f6e3ac1d..d246eae6 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/LobstersPagingSource.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/LobstersPagingSource.kt @@ -3,17 +3,18 @@ package dev.msfjarvis.claw.android.paging import androidx.paging.PagingSource import androidx.paging.PagingState import dev.msfjarvis.claw.model.LobstersPost -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext class LobstersPagingSource( private val getMorePosts: suspend (Int) -> List, + private val ioDispatcher: CoroutineDispatcher, ) : PagingSource() { override suspend fun load(params: LoadParams): LoadResult { return try { val page = params.key ?: 1 - val posts = withContext(Dispatchers.IO) { getMorePosts(page) } + val posts = withContext(ioDispatcher) { getMorePosts(page) } LoadResult.Page( data = posts, diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt index fb90623c..ce237457 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt @@ -5,12 +5,13 @@ import androidx.lifecycle.viewModelScope import androidx.paging.Pager import androidx.paging.PagingConfig 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.ui.toLocalDateTime import dev.msfjarvis.claw.api.LobstersApi import dev.msfjarvis.claw.database.local.SavedPost import javax.inject.Inject -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -24,16 +25,19 @@ constructor( private val api: LobstersApi, private val savedPostsRepository: SavedPostsRepository, private val postDetailsRepository: PostDetailsRepository, + @IODispatcher private val ioDispatcher: CoroutineDispatcher, ) : ViewModel() { private var hottestPostsPagingSource: LobstersPagingSource? = null private var newestPostsPagingSource: LobstersPagingSource? = null private val hottestPostsPager = Pager(PagingConfig(20)) { - LobstersPagingSource(api::getHottestPosts).also { hottestPostsPagingSource = it } + LobstersPagingSource(api::getHottestPosts, ioDispatcher).also { + hottestPostsPagingSource = it + } } private val newestPostsPager = Pager(PagingConfig(20)) { - LobstersPagingSource(api::getNewestPosts).also { newestPostsPagingSource = it } + LobstersPagingSource(api::getNewestPosts, ioDispatcher).also { newestPostsPagingSource = it } } val hottestPosts @@ -58,7 +62,7 @@ constructor( } fun toggleSave(post: SavedPost) { - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch(ioDispatcher) { val saved = isPostSaved(post) if (saved) { savedPostsRepository.removePost(post) @@ -69,14 +73,13 @@ constructor( } suspend fun getPostComments(postId: String) = - withContext(Dispatchers.IO) { + withContext(ioDispatcher) { val details = api.getPostDetails(postId) val extendedDetails = postDetailsRepository.getExtendedDetails(details) extendedDetails } - suspend fun getUserProfile(username: String) = - withContext(Dispatchers.IO) { api.getUser(username) } + suspend fun getUserProfile(username: String) = withContext(ioDispatcher) { api.getUser(username) } fun refreshHottestPosts() { hottestPostsPagingSource?.invalidate() diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt index 9e4cff2e..0fa387a4 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt @@ -2,29 +2,31 @@ package dev.msfjarvis.claw.android.viewmodel import app.cash.sqldelight.coroutines.asFlow import app.cash.sqldelight.coroutines.mapToList +import dev.msfjarvis.claw.android.injection.DatabaseDispatcher import dev.msfjarvis.claw.database.LobstersDatabase import dev.msfjarvis.claw.database.local.SavedPost import io.github.aakira.napier.Napier import javax.inject.Inject -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext class SavedPostsRepository @Inject constructor( database: LobstersDatabase, + @DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher, ) { private val savedPostQueries = database.savedPostQueries - val savedPosts = savedPostQueries.selectAllPosts().asFlow().mapToList() + val savedPosts = savedPostQueries.selectAllPosts().asFlow().mapToList(dbDispatcher) suspend fun savePost(post: SavedPost) { Napier.d(tag = TAG) { "Saving post: ${post.shortId}" } - withContext(Dispatchers.IO) { savedPostQueries.insertOrReplacePost(post) } + withContext(dbDispatcher) { savedPostQueries.insertOrReplacePost(post) } } suspend fun removePost(post: SavedPost) { Napier.d(tag = TAG) { "Removing post: ${post.shortId}" } - withContext(Dispatchers.IO) { savedPostQueries.deletePost(post.shortId) } + withContext(dbDispatcher) { savedPostQueries.deletePost(post.shortId) } } private companion object {