6
votes

While learning how to use Kotlin Coroutines recently, have been read several relevant articles. But one of them confuse me: Coroutines On Android (part III): Real work

As it pointed out:

Note: Room uses its own dispatcher to run queries on a background thread. Your code should not use withContext(Dispatchers.IO) to call suspending room queries. It will complicate the code and make your queries run slower.

It seems to make sense at the time I saw these paragraph, but when I open an Android project and trying to dive into, the problem shows up, Android Studio warns me:

suspend function 'yourMethod' should be called only from a coroutine or another suspend function

I'm now freezing here, because the article told me not to use withContext(Dispatchers.IO). And I am now wondering should I use withContext(Dispatchers.Main) or use GlobalScope.launch to run my queries?

1
"And I am now wondering should I use withContext(Dispatchers.Main) or use GlobalScope.launch to run my queries?" -- use launch() (or perhaps async() and await()) with a suitable CoroutineScope. That could be GlobalScope, but usually there are better options (viewModelScope on a ViewModel, lifecycleScope on an activity, viewLifecycleScope on a fragment, a custom CoroutineScope as seen here, etc. - CommonsWare
@CommonsWare thanks, I am looking for a solution for work that shouldn’t be canceled, and the link you provide is exactly what I'm looking for, I'll check this out. Thank you for your help! - Carter Chen
try withContext(NonCancellable) {} if you don't want your suspend fun operations cancelled - diousk
@sasikumar your solution seems no help to this question. The "suspend" keyword in your project is marked as "redundant" by Android Studio. - Carter Chen

1 Answers

1
votes

I am also new to coroutines and here is what I understand so far. If I want to interact with a database, I do

lifecycleScope.launch {
        //this is still the main thread
        //interact with database
        NoteDatabase(this).getNoteDao().addNote(Note(id=0, title = "TITLE", note = "BODY"))
        //signature of addNote: @Insert suspend fun addNote(note: Note)
}

Using lifecycleScope ensures you don't do anything after the activity or fragment is destroyed, but maybe it makes more sense to use GlobalScope since you don't want an add/save operation to be cancelled when exiting an activity where you edit a database entry.

When using "suspend", there is no guarantee that the function is non-blocking. If there is blocking code, it's the programmer's responsibility to change the coroutine context. I confirmed that Room does indeed change context by checking the build, so you don't have to worry about changing context yourself: RoomDao implementation

CoroutinesRoom.execute