J'ai lu des sujets similaires mais je n'ai pas trouvé de réponse appropriée:
Dans ma classe Repository
classe j'ai un rhume Flow
que je veux partager à 2 Presenters
/ViewModels
_ Mon choix est d'utiliser shareIn
Opérateur.
Jetons un coup d'œil sur Android Docs 'Exemple:
val latestNews: Flow<List<ArticleHeadline>> = flow {
...
}.shareIn(
externalScope, // e.g. CoroutineScope(Dispatchers.IO)?
replay = 1,
started = SharingStarted.WhileSubscribed()
)
Quels documents suggèrent que externalScope
paramètre:
Un coroutinécope utilisé pour partager le flux. Cette portée devrait vivre plus longtemps que tout consommateur de maintenir le flux partagé en vie aussi longtemps que nécessaire.
Cependant, à la recherche de réponse sur la façon d'arrêter de souscrire un Flow
, la réponse la plus votée au 2e lien dit:
Une solution n'est pas d'annuler le flux, mais la portée est lancée dans.
Pour moi, ces réponses sont contradictoires dans le cas SharedFlow
. Et malheureusement, mon Presenter
/ViewModel
reçoit toujours les données les plus récentes, même après que son onCleared
a été appelé.
Comment prévenir cela? C'est un exemple de savoir comment je consomme ce Flow
dans mon Presenter
/ViewModel
:
fun doSomethingUseful(): Flow<OtherModel> {
return repository.latestNews.map(OtherModel)
Si cela pourrait aider, j'utilise l'architecture MVI, alors doSomethingUseful
réagit à certaines intention créées par l'utilisateur.
Utilisez SharedFlow. Dans l'exemple ci-dessous, je suis émettant une valeur d'un fragment et la collecte d'un autre.
ViewModel:
class MenuOptionsViewModel : ViewModel() {
private val _option = MutableSharedFlow<String>()
val option = _option.asSharedFlow()
suspend fun setOption(o : String){
_option.emit(o)
}
}
Valeurs émettrices de fragments:
class BottomSheetOptionsFragment : BottomSheetDialogFragment() , KodeinAware{
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
menuViewModel = activity?.run {
ViewModelProviders.of(this).get(MenuOptionsViewModel::class.Java)
} ?: throw Exception("Invalid Activity")
listViewOptions.adapter = ArrayAdapter<String>(
requireContext(),
R.layout.menu_text_item,
options
)
listViewOptions.setOnItemClickListener { adapterView, view, i, l ->
val entry: String = listViewOptions.getAdapter().getItem(i) as String
// here we are emitting values
GlobalScope.launch { menuViewModel.setOption(entry) }
Log.d(TAG, "emitting flow $entry")
dismiss()
}
}
}
Fragment Collecte des valeurs:
class DetailFragment : BaseFragment(), View.OnClickListener, KodeinAware,
OnItemClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
menuViewModel = activity?.run {
ViewModelProviders.of(this).get(MenuOptionsViewModel::class.Java)
} ?: throw Exception("Invalid Activity")
// collecting values
lifecycleScope.launchWhenStarted {
menuViewModel.option.collect {
Log.d(TAG, "collecting flow $it")
}
}
}