Skip to content

Instantly share code, notes, and snippets.

@ConorGarry
Last active May 13, 2020 07:57
Show Gist options
  • Select an option

  • Save ConorGarry/234ea2c449db2470660853bb87bd7769 to your computer and use it in GitHub Desktop.

Select an option

Save ConorGarry/234ea2c449db2470660853bb87bd7769 to your computer and use it in GitHub Desktop.
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext
class CoroutineApiViewModel : ViewModel() {
private val _dataOne = MutableLiveData<UiState<String>>()
val dataOne: LiveData<UiState<String>> = _dataOne
private val _dataTwo = MutableLiveData<UiState<String>>()
val dataTwo: LiveData<UiState<String>> = _dataTwo
private val _dataThree = MutableLiveData<UiState<String>>()
val dataThree: LiveData<UiState<String>> = _dataThree
init {
viewModelScope.launch {
supervisorScope {
_dataOne.repoFetch(this) { getDataOne() }
_dataTwo.repoFetch(this) { getDataTwo() }
_dataThree.repoFetch(this) { getDataThree() }
}
}
}
/**
* Ext function on MutableLiveData<UiState<T>>.
* For streamlining common pattern for fetching data from repo and
* setting state either to Success with fetched data, or Error.
*
* @param scope CoroutineScope For launching coroutine (should be [supervisorScope]
* if used concurrently with other coroutines).
* @param f Function Suspend function that fetches data from repo.
* @param dispatcher CoroutineDispatcher Defaults to IO.
*/
suspend fun <T> MutableLiveData<UiState<T>>.repoFetch(
scope: CoroutineScope,
dispatcher: CoroutineDispatcher = Dispatchers.IO,
f: suspend () -> T,
) {
scope.launch(dispatcher + UiStateExceptionHandler(this)) {
postValue(UiState.Success(f()))
}
}
/**
* CoroutineExceptionHandler for catching Exceptions and posting them to the LiveData State holder.
* @param state MutableLiveData<UiState<T>> State object for propagating Success data or Error Throwable to.
*/
@Suppress("FunctionName")
public fun <T> UiStateExceptionHandler(state: MutableLiveData<UiState<T>>): CoroutineExceptionHandler {
return object : AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler {
override fun handleException(context: CoroutineContext, exception: Throwable) {
state.postValue(UiState.Error(exception))
}
}
}
suspend fun getDataOne(): String {
delay(200)
return "Data One Payload."
}
suspend fun getDataTwo(): String {
delay(200)
error("Runtime error while fetching data two!")
return "Data Two Payload."
}
suspend fun getDataThree(): String {
delay(200)
return "Data Three Payload."
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment