如何在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
相关产品推荐
相关产品推荐

