Skip to content

Instantly share code, notes, and snippets.

@adam-hurwitz
Last active August 30, 2020 15:50
Show Gist options
  • Select an option

  • Save adam-hurwitz/c4e50c771f8849d382f383e74abceeaa to your computer and use it in GitHub Desktop.

Select an option

Save adam-hurwitz/c4e50c771f8849d382f383e74abceeaa to your computer and use it in GitHub Desktop.
UDF - Kotlin Flow vs. Rx: OnEachEvent view effects with Flow
/**
* Used as a wrapper for data that is exposed via an observable that represents an event.
* Developed by Jose Alcérreca.
* See [https://gist.github.com/JoseAlcerreca/5b661f1800e1e654f07cc54fe87441af#file-event-kt]
*/
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.transform
/**
* Returns a flow which performs the given [action] on each value of the original flow's [Event].
*/
public fun <T> Flow<Event<T?>>.onEachEvent(action: suspend (T) -> Unit): Flow<T> = transform { value ->
value.getContentIfNotHandled()?.let {
action(it)
return@transform emit(it)
}
}
@ExperimentalCoroutinesApi
data class _FeedViewEffect(
val _isLoading: MutableStateFlow<Event<Boolean?>> = MutableStateFlow(Event(null))
)
@ExperimentalCoroutinesApi
data class FeedViewEffect(private val _viewEffect: _FeedViewEffect) {
val isLoading: Flow<Event<Boolean?>> = _viewEffect._isLoading.filterNotNull()
}
viewModel.viewEffect.isLoading.onEachEvent { isLoading ->
if (isLoading == true)
progressBar.visibility = VISIBLE
else {
progressBar.visibility = GONE
swipeToRefresh.isRefreshing = false
}
}.launchIn(lifecycleScope)
private fun initFeed(toRetry: Boolean) {
feedRepository.initFeed(pagedListBoundaryCallback(toRetry)).onEach { results ->
when (results.status) {
LOADING -> _viewEffect._isLoading.value = Event(true)
SUCCESS -> {
_viewEffect._isLoading.value = Event(false)
_viewState._feed.value = results.data
}
ERROR -> {
_viewEffect._isLoading.value = Event(false)
}
}
}.launchIn(viewModelScope)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment