Initialize a Kotlin Coroutine Flow and modify its' value after the Flow's creation.
The desired functionality is similar to MutableLiveData's setValue
which allows data to be added to an existing MutableLiveData object.
In the example below setValue
is called on the _feed
MutableLiveData value in FeedViewModel.kt in order to update the value.
This works as expected, emitting the values in FeedFragment.kt
FeedViewState.kt
data class _FeedViewState(
val _feed: MutableLiveData<List<Tweet>> = MutableLiveData()
)
data class FeedViewState(private val _feedViewState: _FeedViewState) {
val feed: LiveData<List<Tweet>> = _feedViewState._feed
}
FeedViewModel.kt
class FeedViewModel(...) : ViewModel() {
private val _feedViewState = _FeedViewState()
val feedViewState = FeedViewState(_feedViewState)
init {
viewModelScope.launch(Dispatchers.IO) {
feedRepository.getFeed().collect { results ->
when (results.status) {
LOADING -> ...
SUCCESS -> withContext(Dispatchers.Main) {
_feedViewState._feed.value = results.data
}
ERROR -> ...
}
}
}
}
}
FeedFragment.kt
class FeedFragment : Fragment() {
override fun onCreateView(...): View? {
viewModel.feedViewState.feed.observe(viewLifecycleOwner){ feed ->
//Do something with the tweets here.
}
return inflater.inflate(R.layout.fragment_feed, container, false)
}
}
In order to implement the same pattern using Kotlin Coroutines the LiveData in the FeedViewState.kt is replaced with Flow. In FeedViewModel.kt the desired result is to add data to the _feed
Flow value. The attempted solutions have been applying map
, and emit
inside of transform
and onCompletion
to the _feed
Flow value.
However, this solution does not emit the desired values from the Flow value in FeedFragment.kt.
FeedViewState.kt
data class _FeedViewState(
val _feed: Flow<List<Tweet>> = flow { }
)
data class FeedViewState(private val _feedViewState: _FeedViewState) {
@ExperimentalCoroutinesApi
val feed: Flow<List<Tweet>> = _feedViewState._feed }
}
FeedViewModel.kt
class FeedViewModel(...) : ViewModel() {
private val _feedViewState = _FeedViewState()
val feedViewState = FeedViewState(_feedViewState)
init {
viewModelScope.launch(Dispatchers.IO) {
feedRepository.getFeed().collect { results ->
when (results.status) {
LOADING -> ...
SUCCESS -> withContext(Dispatchers.Main) {
_feedViewState._feed.map { results.data!! }
}
ERROR -> ...
}
}
}
}
}
FeedFragment.kt
class FeedFragment : Fragment() {
override fun onCreateView(...): View? {
lifecycleScope.launch {
viewModel.feedViewState.feed.collect { tweets ->
//Do something with the tweets here.
}
}
return inflater.inflate(R.layout.fragment_feed, container, false)
}
}
To create flows, use the flow builder APIs. The flow builder function creates a new flow where you can manually emit new values into the stream of data using the emit function. In the following example, a data source fetches the latest news automatically at a fixed interval.
StateFlow and LiveData have similarities. Both are observable data holder classes, and both follow a similar pattern when used in your app architecture. The StateFlow and LiveData do behave differently: StateFlow requires an initial state to be passed into the constructor, while LiveData does not.
Stay organized with collections Save and categorize content based on your preferences. Kotlin coroutines provide an API that enables you to write asynchronous code.
A container for data of a specific primitive type. A buffer is a linear, finite sequence of elements of a specific primitive type.
Kotlin StateFlow is a newer solution compared to Kotlin Channels that allow mutable updates to the Flow value
as well as the ability to immutable observe data streams.
Flow is meant to be self contained. What I would suggest is using ConflatedBroadcastChannel which offers functionality I believe you are looking for but this is currently an experimental feature in kotlin
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With