为什么在 kotlin 中流式收集调用超过两次?
why flow collect call more than twice in kotlin?
嘿,我在 android 从事 kotlin 流程工作。我注意到我的 kotlin 流程 collectLatest
调用了两次,有时甚至更多。我试过 但它对我不起作用。我在我的 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.
原因是collectLatest喜欢背压。如果您一次传递多个项目,流程将只收集最新的,但如果发射之间有一段时间,流程将像最新的一样收集每个项目
已编辑:
您真的需要了解 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
您正在使用 MutableStateFlow
which derives from StateFlow
,StateFlow
具有初始值,您将其指定为 emptyList
:
var conversationMutableStateFlow = MutableStateFlow<List<String>>(emptyList())
所以你第一次在 collectLatest
块中得到 data
时,它是一个空列表。第二次是响应中的列表。
当您调用 collectLatest
时,conversationMutableStateFlow
只有初始值,这是一个空列表,这就是您首先收到它的原因。
你可以把你的StateFlow
改成SharedFlow
,它没有初始值,所以你只会在collectLatest
块中接到一个电话。在 ActivityViewModel
class:
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 ->
// ...
}
嘿,我在 android 从事 kotlin 流程工作。我注意到我的 kotlin 流程 collectLatest
调用了两次,有时甚至更多。我试过 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.
原因是collectLatest喜欢背压。如果您一次传递多个项目,流程将只收集最新的,但如果发射之间有一段时间,流程将像最新的一样收集每个项目
已编辑: 您真的需要了解 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
您正在使用 MutableStateFlow
which derives from StateFlow
,StateFlow
具有初始值,您将其指定为 emptyList
:
var conversationMutableStateFlow = MutableStateFlow<List<String>>(emptyList())
所以你第一次在 collectLatest
块中得到 data
时,它是一个空列表。第二次是响应中的列表。
当您调用 collectLatest
时,conversationMutableStateFlow
只有初始值,这是一个空列表,这就是您首先收到它的原因。
你可以把你的StateFlow
改成SharedFlow
,它没有初始值,所以你只会在collectLatest
块中接到一个电话。在 ActivityViewModel
class:
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 ->
// ...
}