Estoy usando Flow en lugar de LiveData para recopilar datos en mi Fragmento. En Fragment AI observe (o más bien recopile) los datos en mi fragment`s onViewCreated así:
lifecycleScope.launchWhenStarted { availableLanguagesFlow.collect { languagesAdapter.setItems(it.allItems, it.selectedItem) } }problema Luego, cuando voy al Fragmento B y luego vuelvo al Fragmento A, mi función de recopilación se llama dos veces. Si vuelvo al Fragmento B y vuelvo a A, entonces la función de recopilación se llama 3 veces. Y así.
Use SharedFlow y aplíquele replayCache.
Restablece el replayCache de este flujo compartido a un estado vacío. Los suscriptores nuevos recibirán solo los valores que se emitieron después de esta llamada, mientras que los suscriptores antiguos seguirán recibiendo valores previamente almacenados en búfer. Para restablecer un flujo compartido a un valor inicial, emita el valor después de esta llamada. más información
private val _reorder = MutableSharedFlow<ViewState<ReorderDto?>>().apply { resetReplayCache() } val reorder: SharedFlow<ViewState<ReorderDto?>> get() = _reorderOcurre debido al complicado ciclo de vida de Fragment . Cuando regresa del Fragmento B al Fragmento A, el Fragmento A se vuelve a unir. Como resultado, onViewCreated del fragmento se llama por segunda vez y observa la misma instancia de Flow por segunda vez . En otras palabras, ahora tiene un flujo con dos observadores, y cuando el flujo emite datos, se llama a dos de ellos.
Use viewLifecycleOwner en onViewCreated de Fragment. Para ser más específico, use viewLifecycleOwner .lifecycleScope.launch en lugar de lifecycleScope.launch. Me gusta esto:
viewLifecycleOwner.lifecycleScope.launchWhenStarted { availableLanguagesFlow.collect { languagesAdapter.setItems(it.allItems, it.selectedItem) } }En Actividad, simplemente puede recopilar datos en onCreate.
lifecycleScope.launchWhenStarted { availableLanguagesFlow.collect { languagesAdapter.setItems(it.allItems, it.selectedItem) } }extensión:
fun <T> Flow<T>.launchWhenStarted(lifecycleOwner: LifecycleOwner) { lifecycleOwner.lifecycleScope.launchWhenStarted { this@launchWhenStarted.collect() } }en el fragmento onViewCreated:
availableLanguagesFlow .onEach { //update view }.launchWhenStarted(viewLifecycleOwner) Prefiero usar ahora repeatOnLifecycle , porque cancela la rutina en curso cuando el ciclo de vida cae por debajo del estado (onStop en mi caso). Mientras no repeatOnLifecycle , la recopilación se suspenderá cuando esté onStop. Echa un vistazo a este artículo .
fun <T> Flow<T>.launchWhenStarted(lifecycleOwner: LifecycleOwner)= with(lifecycleOwner) { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED){ try { this@launchWhenStarted.collect() }catch (t: Throwable){ loge(t) } } } }