malcolms
malcolms

Reputation: 31

how to use values from coroutines outside of coroutines

How do I use the response from a room database outside of the coroutine it was called from

I need to use coroutines to execute a request from a room database, then take this data display it in a recyclerview. The problem I'm having is that I can't get the response from the database to show up outside of the coroutine.

my code.

class seconddisplay : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.second_display)

    GlobalScope.launch {
        val respo = second_Database.getInstance(context = this@seconddisplay).DAO().seeAllcodes()

    }

    second_recyclerview.apply {
        layoutManager = LinearLayoutManager(this@seconddisplay)
        adapter = displayAdapter(respo)
    }
}

I also can't put the recyclerview code within the coroutine because it says you can't touch the hierarchy of the view.

Upvotes: 1

Views: 2205

Answers (2)

Mateo Hervas
Mateo Hervas

Reputation: 585

You could use the respo variable as a global variable of the class.And then use the property withContext(Dispatcher.main) to use the mainthread and wait for the result.Something like this:

private var respo: YourDataType? = null


override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.second_display)
   getRespo()
   
}

private fun getRespo(){
   val supervisorJob = SupervisorJob()
   val coroutineScope = CoroutineScope(Dispatchers.IO + supervisorJob)
   coroutineScope.launch {
      withContext(Dispatchers.Main) {
      respo = second_Database.getInstance(this@seconddisplay).DAO().seeAllcodes()
      second_recyclerview.apply {
      layoutManager = LinearLayoutManager(this@seconddisplay)
        if(respo!=null){
          adapter = displayAdapter(respo)
        }else{//handle respo being null, maybe show a message 
          }
        }
     
      }
   }
   
}

Upvotes: -1

Sergio
Sergio

Reputation: 30645

In Activity or Fragment you can use lifecycleScope to launch a coroutine, by default it runs on the Main coroutine context, therefore you can update your UI from there:

lifecycleScope.launch {
    // call like this if `seeAllcodes()` method is suspend
    val respo = second_Database.getInstance(context = this@seconddisplay).DAO().seeAllcodes() 

    // call like this if `seeAllcodes()` method isn't suspend
    val respo = withContext(Dispatchers.IO) { // runs on background thread
        second_Database.getInstance(context = this@seconddisplay).DAO().seeAllcodes()
    }

    // update UI
    second_recyclerview.apply {
        layoutManager = LinearLayoutManager(this@seconddisplay)
        if (respo != null) {
            adapter = displayAdapter(respo)
        }
    }
}

To use lifecycleScope add next line to dependencies of the app's build.gradle file:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-alpha05"

Upvotes: 2

Related Questions