如何解决Fragment popbackstack 触发器生命周期范围收集
情况
我提交数据 setTripDeliver
,收集工作正常(触发 LOADING,然后触发 SUCCESS)。我按下按钮转到下一个片段 B(使用 replace
)。之后,我按下后退按钮(使用 popbackstack
)。触发收集成功。
相关代码
这些代码位于 FragmentA.kt
内的 onViewCreated
。
private fun startLifeCycle() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
collectTripDeliver()
}
launch {
collectTripReattempt()
}
}
}
}
这些代码何时在按钮 setonClickListener
处提交数据。
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewmodel.setTripDeliver(
verificationCode,remark
)
}
收集流的方法collectTripReattempt()
private suspend fun collectTripReattempt() {
viewmodel.tripReattempt.collect {
when (it) {
is Resource.Initialize -> {
}
is Resource.Loading -> {
Log.i("???","collectTripReattempt loading")
handleSaveEarly()
}
is Resource.Success -> {
val error = it.data?.error
if (error == null) {
Tools.showToast(requireContext(),"Success Reattempt")
Log.i("???","collectTripReattempt Success")
} else {
Tools.showToast(requireContext(),"$error")
}
handleSaveEnding()
}
is Resource.Error -> {
handleSaveEnding()
}
}
}
}
private val _tripDeliver =
MutableStateFlow<Resource<TripDeliverResponse>>(Resource.Initialize())
val tripDeliver: StateFlow<Resource<TripDeliverResponse>> = _tripDeliver
suspend fun setTripDeliver(
verificationCode: String?,remark: String?
) {
_tripDeliver.value = Resource.Loading()
try {
val result = withContext(iodispatcher) {
val tripDeliverParameter = DeliverParameter(
verificationCode,remark
)
val response = appRepository.setTripDeliver(tripDeliverParameter)
Resource.getResponse { response }
}
_tripDeliver.value = result
} catch (e: Exception) {
when (e) {
is IOException -> _tripDeliver.value =
Resource.Error(messageInt = R.string.no_internet_connection)
else -> _tripDeliver.value =
Resource.Error("Trip Deliver Error: " + e.message)
}
}
}
Logcat
2021-07-09 19:56:10.946 7446-7446/com.package.app I/???: collectTripReattempt loading
2021-07-09 19:56:11.172 7446-7446/com.package.app I/???: collectTripReattempt Success
2021-07-09 19:56:17.703 7446-7446/com.package.app I/???: collectTripReattempt Success
如您所见,在我按下后退按钮 (Success
) 后,最后一个 popbackstack
被再次调用
问题
如何让它只触发一次?是我实现它的方式错误吗?提前致谢。
解决方法
这不是您的实现问题,这是因为 stateIn() 在您的 viewModel
中使用将常规流转换为 stateFlow
如果根据您的代码片段 success 再次触发,那么为什么 loading 没有触发?
根据文章,当您离开屏幕并返回时,它会显示 latest cached value
,您会看到最新的缓存值。
资源:
https://medium.com/androiddevelopers/migrating-from-livedata-to-kotlins-flow-379292f419fb The latest value will still be cached so that when the user comes back to it,the view will have some data immediately.
我认为这是因为coldFlow,你需要一个HotFlow。另一种选择是尝试隐藏和显示片段,而不是替换。另一个解决方案是将此代码保留在 viewModel 中。
,在我看来,我认为你在 lifeScope 中使用协程的方式是不正确的。 FragmentA 的 lifeScope 状态再次处于 Started 后,协程将重新启动:
launch {
collectTripDeliver()
}
launch {
collectTripReattempt()
}
所以我认为:你需要这样修改:
private fun startLifeCycle() {
viewLifecycleOwner.lifecycleScope.launch {
launch {
collectTripDeliver()
}
launch {
collectTripReattempt()
}
}
}
,
我找到了解决方案,感谢@Nurseyit Tursunkulov 给我一个线索。我必须使用 SharedFlow
。
在 ViewModel
处,我将初始化替换为以下内容:
private val _tripDeliver = MutableSharedFlow<Resource<TripDeliverResponse>>(replay = 0)
val tripDeliver: SharedFlow<Resource<TripDeliverResponse>> = _tripDeliver
在 replay
我必须使用 0
,所以这个 SharedFlow
将触发一次。接下来,将 _tripDeliver.value
更改为 _tripDeliver.emit()
,如下所示:
fun setTripDeliver(
verificationCode: String?,remark: String?
) = viewModelScope.launch {
_tripDeliver.emit(Resource.Loading())
if (verificationCode == null && remark == null) {
_tripDeliver.emit(Resource.Error("Remark cannot be empty if verification is empty"))
return@launch
}
try {
val result = withContext(ioDispatcher) {
val tripDeliverParameter = DeliverParameter(
verificationCode,remark,)
val response = appRepository.setTripDeliver(tripDeliverParameter)
Resource.getResponse { response }
}
_tripDeliver.emit(result)
} catch (e: Exception) {
when (e) {
is IOException -> _tripDeliver.emit(Resource.Error(messageInt = R.string.no_internet_connection))
else -> _tripDeliver.emit(Resource.Error("Trip Deliver Error: " + e.message))
}
}
}
我希望这个答案也能帮助其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。