3

I am new to multithreading and looking for solution for this problem. I am launching a method in coroutine which updates data in my database and if it is updated I would like to update the UI for users. How to this? I cannot put runOnUiThread inside a coroutine. Is there some type of magic like -> when coroutine finished -> then -> runOnUi?

Greetings

6
  • Maybe watch the database for updates and re render the UI after an update is made. Room with LiveData can provide you observables for the same thing Commented Dec 2, 2019 at 10:38
  • Hmm thats a good idea. Will check this :) But is there a solution for await till something what is runing under a coroutine scope is finished? Commented Dec 2, 2019 at 10:41
  • Any suspending function without async keyword will run sequentially in a scope so you can put two functions one to write and other to read from DB. Commented Dec 2, 2019 at 10:50
  • 1
    Take a look at this medium.com/androiddevelopers/… article here the animations on a view are done sequentially as well as simultaneously using coroutines(Edited the link) Commented Dec 2, 2019 at 10:52
  • Thank you :) Such a fresh news (written today :D) Commented Dec 2, 2019 at 10:55

3 Answers 3

4

You don't need to call runOnUiThread as the coroutine will have the main dispatcher as the context.

Let's say you have this helper function to offload work to the I/O thread.

suspend fun <T> withIO(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block)

If you are using a ViewModel, then you can call it like this

viewModelScope.launch {
    val result = withIO { 
        // You are on IO thread here.
        update your database
    }
    // The block will be suspended until the above task is done.
    // You are on UI thread now.
    // Update your UI.
}

If you are not using a ViewModel, you can also use

withContext(Disptachers.Main) {
   val result = withIO {
       // You are on IO thread
   }
   // You are back on the main thread with the result from the task
}
Sign up to request clarification or add additional context in comments.

Comments

1

Coroutine are task that work on different thread. What you really want is wating for changes in database. Coroutine in this idea could work for insert data in db, but listening part is role of ViewModel pattern.

I recently answer similar question to yours:

AutocompleteTextView with room

More specific could be this answer from another user:

Wait until Kotlin coroutine finishes in onCreateView()

Comments

1

So the basic problem is to jumping back to main thread after co-routine finishes

this can be done multiple ways

using launch(Dispatcher.Main)

from main thread init co-routine something like this

//launches coroutine running on main thread
GlobalScope.launch(Dispatchers.Main) {
    updateDb()
}

suspend fun updateDb(){
    //runs on worker thread and returns data
    val value = withContext(Dispatchers.IO){
       saveDataInDb();
    }
    //runs back on main thread
    updateUI(value);
}

However global scope should not be used You can read about that here https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc

using async await

suspend fun saveInDb() {
    val value = GlobalScope.async {
        delay(1000)
        println("thread running on [${Thread.currentThread().name}]")
        10
    }
    println("value =  ${value.await()} thread running on [${Thread.currentThread().name}]")
}

output:

 thread running on [DefaultDispatcher-worker-1]
 value =  10 thread running on [main]
 thread running on [main]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.