Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

182
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda