Sudhir Singh Khanger
06/07/2021, 6:32 AMsomeDbCall()
should be a suspend
function.
private fun someDbCall() { //some db call }
someScope.launch {
someDBCall()
}
Do you have a personal philosophy such as don't use suspend keyword unless the compiler forces you to as I have been reading on Stack overflow?
someScope.launch {
withContext(NonCancellable + <http://Dispatchers.IO|Dispatchers.IO>) { someDBCall() }
}
If you do have a philosophy of not using suspend keyword when not needed then how does construct like withContext affect using them with non-suspend keyword function.gildor
06/07/2021, 7:22 AMgildor
06/07/2021, 7:22 AMgildor
06/07/2021, 7:24 AMSudhir Singh Khanger
06/07/2021, 10:01 AMwithContext
at the time of usage one should prefer using it in the function itself and the reason for it is that one might forget to call it with proper dispatcher at the time of usage and would end up using it like a blocking call.
suspend fun someDbCall() = withContext(<http://Dispatchers.IO|Dispatchers.IO>) { //some db call }
2. Creating a class with its own scope sort of like GlobalScope is something that I want to learn to do. I saw some documents on it here and here which look like the following.
Approach A
// DO inject an external scope instead of using GlobalScope.
// GlobalScope can be used indirectly. Here as a default parameter makes sense.
class ArticlesRepository(
private val articlesDataSource: ArticlesDataSource,
private val externalScope: CoroutineScope = GlobalScope,
private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {
// As we want to complete bookmarking the article even if the user moves
// away from the screen, the work is done creating a new coroutine
// from an external scope
suspend fun bookmarkArticle(article: Article) {
externalScope.launch(defaultDispatcher) {
articlesDataSource.bookmarkArticle(article)
}
.join() // Wait for the coroutine to complete
}
}
Approach B
This will likely be moved Dagger module
class MyApplication : Application() {
// No need to cancel this scope as it'll be torn down with the process
val applicationScope = CoroutineScope(SupervisorJob() + otherConfig)
}
And
class Repository(
private val externalScope: CoroutineScope,
private val ioDispatcher: CoroutineDispatcher
) {
suspend fun doWork() {
withContext(ioDispatcher) {
doSomeOtherWork()
externalScope.launch {
// if this can throw an exception, wrap inside try/catch
// or rely on a CoroutineExceptionHandler installed
// in the externalScope's CoroutineScope
veryImportantOperation()
}.join()
}
}
}
3. What is your view on when to use suspend function? On a theoretical scale, I can see it means ability to pause and resume code execution but it doesn't make sense to me. Say I run some call on a db do they need to be paused/resumed?
4. Do constructs like withContext()
treat suspend and non-suspend function differently?Sudhir Singh Khanger
06/07/2021, 12:17 PMsuspend
keyword.
Room will use different Dispatchers for transactions and queries. These are derived from the executors you provide when building your Database or by default will use the Architecture Components IO executor. This is the same executor that would be used by LiveData to do background work.For point 1, I think I will go with approach B which is to create a
CoroutineScope
with SupervisorJob()
in my Dagger module so it can be injected in classes like my DB manager.Colton Idle
06/07/2021, 3:40 PMgildor
06/08/2021, 5:51 AMSudhir Singh Khanger
06/08/2021, 12:16 PMapplicationScope
. What I ended up doing is create a CoroutineScope
in the Database module of Dagger. That way it is unlikely to be cancelled by a future developer.
@Singleton
@Provides
@Named("DbCoroutineScope")
fun provideDbCoroutineScope(): CoroutineScope = CoroutineScope(SupervisorJob())
Then I am using approach A but the only thing that I find weird is that because I am calling .join()
so I have to make the function a suspend function which would have to be called from another suspend function.
class ArticlesRepository(
private val articlesDataSource: ArticlesDataSource,
@Named("DbCoroutineScope") private val externalScope: CoroutineScope
) {
suspend fun bookmarkArticle(article: Article) {
externalScope.launch() { articlesDataSource.bookmarkArticle(article) }.join()
}
gildor
06/09/2021, 3:18 AM