You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从另一个Activity返回时StateFlow未触发Loading()的问题解决

问题场景

现有两个Activity:Activity Menu和Activity Detail。流程为:进入Activity Menu,点击按钮跳转至Activity Detail,在Activity Detail中更新数据。按下返回键回到Activity Menu时,仅触发了Resource Success状态,Resource Loading状态未被触发。

相关代码

1. Resource密封类

sealed class Resource<T>(
    val data: T? = null,
    val message: String? = null,
    val messageInt: Int? = null,
    val code: Int? = null,
    val errorReader: Reader? = null,
) {
    class Initialize<T> : Resource<T>()
    class Loading<T>(data: T? = null) : Resource<T>(data)
    class Success<T>(data: T?) : Resource<T>(data)
    class Error<T>(
        message: String? = null,
        messageInt: Int? = null,
        data: T? = null,
        code: Int? = null,
        errorReader: Reader? = null
    ) :
        Resource<T>(data, message, messageInt, code, errorReader)
}

2. ViewModel代码

private val _itemList = MutableStateFlow<Resource<Int>>(Resource.Initialize())
val itemList: StateFlow<Resource<Int>> = _itemList

init {
    viewModelScope.launch {
        getItemList()
    }
}

suspend fun getItemList() = viewModelScope.launch {
    _itemList.emit(Resource.Loading())

    val data = withContext(ioDispatcher + coroutineExceptionHandler) {
        return@withContext quickSave.getInt(Constant.BROKEN_TOTE_LIST_COUNT, 0)
    }
    
    // 第二次仅触发此Success
    _itemList.emit(Resource.Success(data = data))
}

3. Activity代码

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityToteBrokenBinding.inflate(layoutInflater)
    val root = binding.root
    setContentView(root)

    startLifeCycle()
}

private fun startLifeCycle() {
    lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            launch {
                collectItemList()
            }
        }
    }
}

private suspend fun collectItemList() {
    viewModel.itemList.collectLatest {
        when (it) {
            is Resource.Initialize -> {
            }
            is Resource.Loading -> {
                Log.i("???","Resource Loading")
                showLoading()
            }
            is Resource.Success -> {
                Log.i("???","Resource Success")
                handleSuccess()
                hideLoading()
            }
            is Resource.Error -> {
                hideLoading()
            }
        }
    }
}
输出日志
---------------------------- PROCESS STARTED (30051) for package com.company.com ----------------------------
2022-09-29 12:21:51.977 30051-30051 ???                     com.company.com                 I  Resource Loading
2022-09-29 12:21:52.137 30051-30051 ???                     com.company.com                 I  Resource Success
2022-09-29 12:22:10.839 30051-30051 ???                     com.company.com                 I  Resource Success
问题

如何实现每次从Activity Detail返回时,都能触发Resource Loading状态?


解决方案

问题核心是:从Activity Detail返回时,Activity Menu回到STARTED生命周期,但ViewModel的getItemList()未被重新调用,且StateFlow会向新订阅者重放最新的Success状态,因此只会触发Success。要实现每次返回都触发Loading,可按以下方式调整:

1. 主动在Activity回到前台时触发数据刷新

在Activity Menu中重写onResume()方法,主动调用ViewModel的getItemList(),强制重新执行加载流程,先发送Loading再发送Success。

修改后的Activity代码:

override fun onResume() {
    super.onResume()
    lifecycleScope.launch {
        viewModel.getItemList()
    }
}

2. 可选:用SharedFlow替代StateFlow(避免状态重放)

如果不需要StateFlow的状态重放特性,可以将_itemList改为MutableSharedFlow,设置replay = 0,这样新订阅不会收到历史状态,只有主动调用getItemList()时才会发送新的状态流。注意要保证Activity启动时也调用getItemList()。

修改后的ViewModel代码:

private val _itemList = MutableSharedFlow<Resource<Int>>(replay = 0)
val itemList: SharedFlow<Resource<Int>> = _itemList

// 保持init中的调用,确保首次启动加载数据
init {
    viewModelScope.launch {
        getItemList()
    }
}

关键原理

  • StateFlow默认会向新订阅者重放最新状态,所以从Detail返回时,Activity重新订阅会直接收到之前的Success,不会触发新的Loading。
  • 主动在Activity回到前台时调用getItemList(),会强制ViewModel重新发送Loading和Success状态,从而实现返回时触发Loading的需求。

内容的提问来源于stack exchange,提问作者Ticherhaz FreePalestine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 09:15:37