Search code examples
androidandroid-livedataandroid-architecture-components

LiveData lazy init with coroutines not working


I want to load data from an API when activity is started. Currently, I call a view model's method from the activity to load data and it's working fine, but I don't know if it's the best way to do it:

Activity

override fun onCreate(savedInstanceState: Bundle?) {
  //initialize stuff...
  viewModel.myData.observe(this) {
    //do things with the data
  }
  lifeCycleScope.launch { viewModel.loadData() }
}

ViewModel

class MyViewModel : ViewModel() {

  val myData = MutableLiveData<MyData>()

  suspend fun loadData() = withContext(Dispatchers.IO) {
     val data = api.getData()
     withContext(Dispatchers.Main) {
       myData.value = data
     }
  }

}

I have seen some examples using lazy initialization, but I don't know how to implement it with coroutines. I have tried this:

Activity

override fun onCreate(savedInstanceState: Bundle?) {
    //initialize stuff...
    viewModel.myData().observe(this) {
        //do things with the data
    }
}

ViewModel

private val myData : MutableLiveData<MyData> by lazy {
    MutableLiveData<MyData>().also {
        viewModelScope.launch { 
            loadData()
        }    
    }
}

fun myData() = myData

suspend fun loadData() = // same as above

But data is not fetched and nothing is displayed.


Solution

  • If you've added dependency livedata-ktx then you can use livedata builder to also have API call in same block and emit. Checkout how you can do it:

    class MyViewModel : ViewModel() {
    
        val myData: LiveData<MyData> = liveData {
            val data = api.getData() // suspended call
            emit(data) // emit data once available
        }
    }