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

如何在Jetpack Compose单例Repository中实现独立可观测倒计时?

改造单例Repository实现全局可观测后台倒计时

改造后的MyRepository实现

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class MyRepository @Inject constructor(
    // 注入Application级别CoroutineScope,替代不安全的GlobalScope
    private val applicationScope: CoroutineScope
) {
    // 内部可变StateFlow存储倒计时值,初始为1小时(3600000ms)
    private val _timer = MutableStateFlow(60 * 60 * 1000)
    // 对外暴露只读StateFlow,防止外部篡改数据
    val timer: StateFlow<Int> = _timer

    init {
        // 在应用级Scope中启动倒计时,生命周期与应用绑定
        applicationScope.launch(Dispatchers.Default) {
            startTimer()
        }
    }

    private suspend fun startTimer() {
        while (_timer.value > 0) {
            delay(1000)
            // 更新StateFlow值,自动通知所有订阅页面
            _timer.value -= 1000
        }
    }
}

关键改动说明

  • 替换全局CoroutineScope:弃用GlobalScope(易引发内存泄漏),改用依赖注入的applicationScope,确保倒计时逻辑随应用生命周期稳定运行。
  • StateFlow实现可观测状态:用MutableStateFlow替代普通变量,它是热流类型,能持续向订阅者推送最新状态,完美适配跨页面状态同步需求。
  • 封装数据修改逻辑:对外仅暴露只读StateFlow,所有倒计时修改操作限制在Repository内部,符合单一职责原则。

页面Composable使用示例

在A、C页面中订阅StateFlow即可实时显示倒计时:

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontSize
import androidx.compose.ui.unit.sp

@Composable
fun ScreenA(myRepository: MyRepository) {
    // 将StateFlow转换为Composable可感知的State,自动触发UI重组
    val remainingMillis by myRepository.timer.collectAsState()
    val timeText = formatMillisToTime(remainingMillis)

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center
    ) {
        Text(text = "剩余时间:$timeText", fontSize = 20.sp)
        // 其他页面内容...
    }
}

@Composable
fun ScreenC(myRepository: MyRepository) {
    val remainingMillis by myRepository.timer.collectAsState()
    val timeText = formatMillisToTime(remainingMillis)

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center
    ) {
        Text(text = "剩余时间:$timeText", fontSize = 20.sp)
        // 其他页面内容...
    }
}

// 辅助工具:将毫秒转换为时分秒格式
private fun formatMillisToTime(millis: Int): String {
    val totalSeconds = millis / 1000
    val hours = totalSeconds / 3600
    val minutes = (totalSeconds % 3600) / 60
    val seconds = totalSeconds % 60
    return String.format("%02d:%02d:%02d", hours, minutes, seconds)
}

效果验证

  • 应用启动后,倒计时自动在后台启动,切换到B页面时仍持续运行,不受页面生命周期影响。
  • A、C页面会实时同步显示剩余倒计时,从B页面进入C时,直接加载当前最新的剩余时间值并继续实时更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:20:52