android 为什么在Kotlin中会有两次以上的流付费呼叫?

balp4ylt  于 2023-04-10  发布在  Android
关注(0)|答案(3)|浏览(165)

嘿,我在android中使用Kotlin流。我注意到我的kotlin流collectLatest调用了两次,有时甚至更多。我尝试了这个answer,但它对我不起作用。我在我的collectLatest函数中打印日志,它打印日志。我正在添加代码

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

   .....
}

我不明白为什么这是调用两次。我附加日志

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

正如你所看到的,它调用了两次。但是我加载的数据比它调用的多两倍。我不明白为什么它调用了不止一次。有人能指导我做错了什么吗?如果你需要完整的代码,我正在添加我的项目link

3b6akqbq

3b6akqbq1#

您使用的MutableStateFlow是从StateFlow派生而来的,StateFlow有初始值,您将其指定为emptyList

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

因此,第一次在collectLatest块中得到data时,它是一个空列表,第二次是从响应中得到的列表。
当你调用collectLatest时,conversationMutableStateFlow只有初始值,这是一个空列表,这就是为什么你首先接收它。
你可以把StateFlow改成SharedFlow,因为它没有初始值,所以你只会在collectLatest块中得到一个调用。在ActivityViewModel类中:

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

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

或者,如果你想坚持使用StateFlow,你可以filter你的数据:

viewModel.conversationMutableStateFlow.filter { data ->
                data.isNotEmpty()
            }.collectLatest { data ->
                // ...
            }
rsaldnfx

rsaldnfx2#

原因是collectLatest类似于backpressure。如果您一次传递多个项目,则flow将只收集latest,但如果在发出之间有一些时间,则flow将收集每个latest
编辑:你真的需要阅读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()
}
}

删除ActivityViewModel并将该逻辑添加到FragmentViewModel。还要注意,如果可以使用普通的ViewModel,则不需要使用AndroidViewModel。仅当需要访问Application或其Context时才使用AndroidViewModel

m528fe3b

m528fe3b3#

尝试替换

lifecycleScope.launchWhenStarted

viewLifecycleOwner.lifecycleScope.launch

相关问题