13

Expected

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)
    }
}

Observed

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)
    }
}

2 Answers 2

9

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.