2

I have view model and I use live data. Which one is recommended to use and why? In main thread setValue or in IO thread postValue() or in main thread postValue()

fun getProductInfoFromWebService(barcode: String, url: String) {
    viewModelScope.launch(Dispatchers.IO) {
        val response = productInfoRepo.getProductInfoFromWebService(barcode, url)
        withContext(Dispatchers.Main) {
            _productInfoFromWebService.value = response
        }
    }
}


fun getProductInfoFromWebService(barcode: String, url: String) {
    viewModelScope.launch(Dispatchers.IO) {
        val response = productInfoRepo.getProductInfoFromWebService(barcode, url)
        withContext(Dispatchers.Main) {
            _productInfoFromWebService.postValue(response)
        }
    }
}


    fun getProductInfoFromWebService(barcode: String, url: String) {
    viewModelScope.launch(Dispatchers.IO) {
        val response = productInfoRepo.getProductInfoFromWebService(barcode, url)
        _productInfoFromWebService.postValue(response)
    }
}
Kanan
  • 203
  • 1
  • 15
  • In general, it is recommended to use postValue when working with LiveData in a background thread. – Usama Altaf Jan 05 '23 at 11:10
  • This is because postValue is safe to use from any thread, including background threads, and it will automatically update the value on the main thread for you. On the other hand, setValue should only be used when you are already on the main thread, as it is not safe to call setValue from a background thread. – Usama Altaf Jan 05 '23 at 11:10
  • I added another fun , which one is the best? If postValue() always best why setValue() is used? – Kanan Jan 05 '23 at 11:21

1 Answers1

0

None of the above. The general convention in Android is to make the main thread the default. This is why viewModelScope defaults to Dispatchers.Main.immediate. For the vast majority of launched coroutines, you will not be changing the dispatcher at the launch site.

Furthermore, it is Kotlin coroutines convention for a suspend function to internally delegate to a specific dispatcher if it needs one. You should never need to specify a dispatcher to call a suspend function.

Your code should look like this:

fun getProductInfoFromWebService(barcode: String, url: String) {
    viewModelScope.launch {
        _productInfoFromWebService.value = productInfoRepo.getProductInfoFromWebService(barcode, url)
    }
}

If you were calling a blocking function directly in your launch block, you would usually surround that code with withContext(Dispatchers.IO). But again, this is unnecessary if you are calling a suspend function (unless you improperly designed your suspend function).

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • But if I launch in IO thread, first fun is better then other yes? – Kanan Jan 06 '23 at 05:24
  • I would pick the third one since it’s concise. But the only reason to launch in IO is if you are working with blocking functions directly and don’t need to do anything on the main thread. – Tenfour04 Jan 06 '23 at 13:14
  • I think the main question was whether where to emit the value to the LiveData. Your answer is interesting and implies that any option will work, the simpler (not necessarily the better) being to run suspending functions with the Main dispatcher without ever switching context. For me the question remains, is it better to switch context to the main dispatcher to emit a value or is it better to keep the current context and emit the value using `postValue()`? – Vince Jun 27 '23 at 21:41
  • 1
    @Vince, that's two ways of doing the same thing, so neither is really better, although `postValue` is more concise so I would personally do that. But, like I said, you typically will be on the Main dispatcher in your coroutines if you're following conventions so the point is moot. – Tenfour04 Jun 28 '23 at 01:36