Je peux observer LiveData à partir de plusieurs fragments. Puis-je le faire avec Flow? Si oui, alors comment?
Oui. Vous pouvez le faire avec emit
et collect
. Think emit
est similaire aux données en direct postValue
et collect
est similaire à observe
. Donnons un exemple.
Dépôt
// I just faked the weather forecast
val weatherForecast = listOf("10", "12", "9")
// This function returns flow of forecast data
// Whenever the data is fetched, it is emitted so that
// collector can collect (if there is any)
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?) {
// Collect is suspend function. So you have to call it from a
// coroutine scope. You can create a new coroutine or just use
// lifecycleScope
// https://developer.android.com/topic/libraries/architecture/coroutines
lifecycleScope.launch {
viewModel.getWeatherForecastEveryTwoSeconds().collect {
// Use the weather forecast data
// This will be called 3 times since we have 3
// weather forecast data
}
}
}
Nous pouvons avoir plusieurs LiveData à partir d'un seul LiveData en utilisant map & switchMap. Existe-t-il un moyen d'avoir plusieurs flux à partir d'un seul flux source?
Le flux est très pratique. Vous pouvez simplement créer un flux à l'intérieur du flux. Supposons que vous souhaitiez ajouter un signe de degré à chacune des données de prévisions météorologiques.
ViewModel
fun getWeatherForecast(): Flow<String> {
return flow {
forecastRepository
.getWeatherForecastEveryTwoSeconds(spendingDetailsRequest)
.map {
it + " °C"
}
.collect {
// This will send "10 °C", "12 °C" and "9 °C" respectively
emit(it)
}
}
}
Ensuite, collectez les données dans le fragment identique à # 1. Ici, ce qui se passe, c'est que le modèle de vue collecte les données du référentiel et que le fragment collecte les données du modèle de vue.
En utilisant MutableLiveData, je peux mettre à jour les données de n'importe où en utilisant la référence de variable. Existe-t-il un moyen de faire de même avec Flow?
Vous ne pouvez pas émettre de valeur en dehors du flux. Le bloc de code à l'intérieur du flux n'est exécuté que lorsqu'il existe un collecteur. Mais vous pouvez convertir le flux en données en direct en utilisant l'extension asLiveData de LiveData.
ViewModel
fun getWeatherForecast(): LiveData<String> {
return forecastRepository
.getWeatherForecastEveryTwoSeconds()
.asLiveData() // Convert flow to live data
}
Dans votre cas, vous pouvez le faire
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
}
Éditer
Merci à @mark pour son commentaire. La création d'un nouveau flux dans le modèle de vue pour la getWeatherForecast
fonction n'est en fait pas nécessaire. Il pourrait être réécrit comme
fun getWeatherForecast(): Flow<String> {
return forecastRepository
.getWeatherForecastEveryTwoSeconds(spendingDetailsRequest)
.map {
it + " °C"
}
}