The new LiveData can be used as a replacement for RxJava\'s observables in some scenarios. However, unlike Observable
, LiveData
has no callback for
Just some implementation of the method from Chris Cook's answer:
At first, we need the object that will contain response data and exceptions:
/**
* A generic class that holds a value with its loading status.
*
* @see Sample apps for Android Architecture Components
*/
data class Resource(val status: Status, val data: T?, val exception: Throwable?) {
enum class Status {
LOADING,
SUCCESS,
ERROR,
}
companion object {
fun success(data: T?): Resource {
return Resource(Status.SUCCESS, data, null)
}
fun error(exception: Throwable): Resource {
return Resource(Status.ERROR, null, exception)
}
fun loading(): Resource {
return Resource(Status.LOADING, null, null)
}
}
}
And then my own invention - AsyncExecutor.
This small class do 3 important things:
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
class AsyncExecutor {
companion object {
fun run(callback: () -> T): LiveData> {
val resourceData: MutableLiveData> = MutableLiveData()
Thread(Runnable {
try {
resourceData.postValue(Resource.loading())
val callResult: T = callback()
resourceData.postValue(Resource.success(callResult))
} catch (e: Throwable) {
resourceData.postValue(Resource.error(e))
}
}).start()
return resourceData
}
}
}
Then you can create a LiveData in your ViewModel, contains the result of your callback or exception:
class GalleryViewModel : ViewModel() {
val myData: LiveData>
init {
myData = AsyncExecutor.run {
// here you can do your synchronous operation and just throw any exceptions
return MyData()
}
}
}
And then you can get your data and any exceptions in the UI:
class GalleryFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
galleryViewModel = ViewModelProviders.of(this).get(GalleryViewModel::class.java)
// ...
// Subscribe to the data:
galleryViewModel.myData.observe(viewLifecycleOwner, Observer {
when {
it.status === Resource.Status.LOADING -> {
println("Data is loading...")
}
it.status === Resource.Status.ERROR -> {
it.exception!!.printStackTrace()
}
it.status === Resource.Status.SUCCESS -> {
println("Data has been received: " + it.data!!.someField)
}
}
})
return root
}
}