Hola, estoy trabajando en kotlin flow en android. Noté que mi kotlin flow collectLatest está llamando dos veces y, a veces, incluso más. Intenté esta respuesta pero no funcionó para mí. Imprimí el registro dentro de mi función collectLatest , imprimí el registro. estoy agregando el codigo
MainActivity.kt
class MainActivity : AppCompatActivity(), CustomManager { private val viewModel by viewModels<ActivityViewModel>() private lateinit var binding: ActivityMainBinding private var time = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setupView() } private fun setupView() { viewModel.fetchData() lifecycleScope.launchWhenStarted { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.conversationMutableStateFlow.collectLatest { data -> Log.e("time", "${time++}") .... } } } } }ActivityViewModel.kt
class ActivityViewModel(app: Application) : AndroidViewModel(app) { var conversationMutableStateFlow = MutableStateFlow<List<ConversationDate>>(emptyList()) fun fetchData() { viewModelScope.launch { val response = ApiInterface.create().getResponse() conversationMutableStateFlow.value = response.items } } ..... }No entiendo por qué esto está llamando dos veces. estoy adjuntando registros
2022-01-17 22:02:15.369 8248-8248/com.example.fragmentexample E/time: 0 2022-01-17 22:02:15.629 8248-8248/com.example.fragmentexample E/time: 1Como puedes ver llama dos veces. Pero cargo más datos de los que llama más de dos veces. No entiendo por qué llama más de una vez. ¿Puede alguien por favor guiarme lo que estoy haciendo mal. Si necesita el código completo, estoy agregando el enlace de mi proyecto.
Está utilizando un MutableStateFlow que se deriva de StateFlow , StateFlow tiene un valor inicial, lo está especificando como una emptyList :
var conversationMutableStateFlow = MutableStateFlow<List<String>>(emptyList()) Entonces, la primera vez que obtiene data en el bloque collectLatest , es una lista vacía. La segunda vez es una lista de la respuesta.
Cuando llama a collectLatest , la conversationMutableStateFlow MutableStateFlow solo tiene un valor inicial, que es una lista vacía, por eso la recibe primero.
Puede cambiar su StateFlow a SharedFlow , no tiene un valor inicial, por lo que solo recibirá una llamada en el bloque collectLatest . En la clase ActivityViewModel :
var conversationMutableStateFlow = MutableSharedFlow<List<String>>() fun fetchData() { viewModelScope.launch { val response = ApiInterface.create().getResponse() conversationMutableStateFlow.emit(response.items) } } O si desea apegarse a StateFlow , puede filter sus datos:
viewModel.conversationMutableStateFlow.filter { data -> data.isNotEmpty() }.collectLatest { data -> // ... }El motivo es collectLatest como contrapresión. Si pasa varios elementos a la vez, el flujo recopilará solo los últimos, pero si hay algún tiempo entre las emisiones, el flujo recopilará cada uno como el último.
EDITADO: Realmente necesita leer sobre la arquitectura MVVM.
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setupView() } private fun setupView() { if (supportFragmentManager.findFragmentById(R.id.fragmentView) != null) return supportFragmentManager .beginTransaction() .add(R.id.fragmentView, ConversationFragment()) .commit() } } Elimine ActivityViewModel y agregue esa lógica a FragmentViewModel . También tenga en cuenta que no necesita usar AndroidViewModel , si puede usar ViewModel simple. Use AndroidViewModel solo cuando necesite acceso a la Application o su Context