I can observe LiveData from multiple Fragments. Can I do this with Flow? If yes then how?
Yes. You can do this with emit
and collect
. Think emit
is similar to live data postValue
and collect
is similar to observe
. Lets give an example.
Repository
val weatherForecast = listOf("10", "12", "9")
fun getWeatherForecastEveryTwoSeconds(): Flow<String> = flow {
for (i in weatherForecast) {
delay(2000)
emit(i)
}
}
ViewModel
fun getWeatherForecast(): Flow<String> {
return forecastRepository.getWeatherForecastEveryTwoSeconds()
}
Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
lifecycleScope.launch {
viewModel.getWeatherForecast().collect {
}
}
}
We can have multiple LiveData from a single LiveData using map& switchMap. Is there any way to have multiple Flow from a single source Flow?
Flow is very handy. You can just create flow inside flow. Lets say you want to append degree sign to each of the weather forecast data.
ViewModel
fun getWeatherForecast(): Flow<String> {
return flow {
forecastRepository
.getWeatherForecastEveryTwoSeconds(spendingDetailsRequest)
.map {
it + " °C"
}
.collect {
emit(it)
}
}
}
Then collect the data in Fragment same as #1. Here what happens is view model is collecting data from repository and fragment is collecting data from view model.
Using MutableLiveData I can update data from anywhere using the variable reference. Is there any way to do the same with Flow?
You cant emit value outside of flow. The code block inside flow is only executed when there is any collector. But you can convert flow to live data by using asLiveData extension from LiveData.
ViewModel
fun getWeatherForecast(): LiveData<String> {
return forecastRepository
.getWeatherForecastEveryTwoSeconds()
.asLiveData()
}
In your case you can do this
private fun getSharedPrefFlow() = callbackFlow {
val sharedPref = context?.getSharedPreferences("SHARED_PREF_NAME", MODE_PRIVATE)
sharedPref?.all?.forEach {
offer(it)
}
}
getSharedPrefFlow().collect {
val key = it.key
val value = it.value
}
Edit
Thanks to @mark for his comment. Creating a new flow in the view model for getWeatherForecast
function is actually unnecessary. It could be re-written as
fun getWeatherForecast(): Flow<String> {
return forecastRepository
.getWeatherForecastEveryTwoSeconds(spendingDetailsRequest)
.map {
it + " °C"
}
}