Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

186
Vistas
why flow collect call more than twice in kotlin?

Hey I am working in kotlin flow in android. I noticed that my kotlin flow collectLatest is calling twice and sometimes even more. I tried this answer but it didn't work for me. I printed the log inside my collectLatest function it print the log. I am adding the code

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
        }
    }

   .....
}

I don't understand why this is calling two times. I am attaching logs

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: 1

As you can see it call two times. But I load more data than it call more than twice. I don't understand why it is calling more than once. Can someone please guide me what I am doing wrong. If you need whole code, I am adding my project link.

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

You are using a MutableStateFlow which derives from StateFlow, StateFlow has initial value, you are specifying it as an emptyList:

var conversationMutableStateFlow = MutableStateFlow<List<String>>(emptyList())

So the first time you get data in collectLatest block, it is an empty list. The second time it is a list from the response.

When you call collectLatest the conversationMutableStateFlow has only initial value, which is an empty list, that's why you are receiving it first.

You can change your StateFlow to SharedFlow, it doesn't have an initial value, so you will get only one call in collectLatest block. In ActivityViewModel class:

var conversationMutableStateFlow = MutableSharedFlow<List<String>>()

fun fetchData() {
    viewModelScope.launch {
        val response = ApiInterface.create().getResponse()
        conversationMutableStateFlow.emit(response.items)
    }
}

Or if you want to stick to StateFlow you can filter your data:

viewModel.conversationMutableStateFlow.filter { data ->
                data.isNotEmpty()
            }.collectLatest { data ->
                // ...
            }
over 4 years ago · Santiago Trujillo Denunciar

0

The reason is collectLatest like backpressure. If you pass multiple items at once, flow will collect latest only, but if there are some time between emits, flow will collect each like latest

EDITED: You really need read about MVVM architecture.

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()
}
}

Delele ActivityViewModel and add that logic to FragmentViewModel. Also notice you don't need use AndroidViewModel, if you can use plain ViewModel. Use AndroidViewModel only when you need access to Application or its Context

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda