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

如何在Jetpack Compose中使用DataStore API实现计时器状态持久化

实现思路

我们使用Jetpack官方推荐的DataStore Preferences实现持久化存储,替代已废弃的SharedPreferences,核心逻辑是ViewModel初始化时读取已存储的时间值,每次时间更新时同步写入Preferences。

步骤1:添加依赖

在Module级别的build.gradle(或build.gradle.kts)中添加DataStore依赖,可替换为最新版本:

dependencies {
    implementation "androidx.datastore:datastore-preferences:1.0.0"
}

步骤2:全局创建DataStore实例

通过Kotlin扩展函数定义全局唯一的DataStore实例,建议放在自定义Application类或顶层工具文件中:

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.preferencesDataStore

// 定义存储文件名称
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "timer_config")
// 定义时间存储的键值
val TIME_KEY = longPreferencesKey("saved_timer_time")

步骤3:改造TimeViewModel

改造后支持初始化读存储、时间变更自动写存储:

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch
import java.io.IOException

class TimeViewModel(private val dataStore: DataStore<Preferences>) : ViewModel() {
    private val _time = MutableLiveData<Long>()
    val time: LiveData<Long> = _time

    init {
        // 初始化时读取已持久化的时间值
        viewModelScope.launch {
            dataStore.data
                .catch { exception ->
                    // 读取异常时返回空配置
                    if (exception is IOException) {
                        emit(emptyPreferences())
                    } else {
                        throw exception
                    }
                }
                .collect { preferences ->
                    val savedTime = preferences[TIME_KEY] ?: 0L
                    _time.postValue(savedTime)
                }
        }
    }

    fun onTimeChange(newTime: Long) {
        _time.value = newTime
        // 时间更新时同步写入Preferences持久化
        viewModelScope.launch {
            dataStore.edit { preferences ->
                preferences[TIME_KEY] = newTime
            }
        }
    }
}

因为ViewModel添加了自定义参数,需要配套创建Factory来实例化:

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences

class TimeViewModelFactory(private val dataStore: DataStore<Preferences>) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(TimeViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return TimeViewModel(dataStore) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

在Activity/Fragment中实例化ViewModel的方式:

// 以Activity为例
val timeViewModel by viewModels<TimeViewModel> {
    TimeViewModelFactory(applicationContext.dataStore)
}

步骤4:修正Composable逻辑

原有代码中LaunchedEffect放在了time变量声明之前,会触发编译错误,调整顺序即可:

import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import java.text.DecimalFormat

@Composable
fun Timer(timeViewModel:TimeViewModel = viewModel()){
    val time: Long by timeViewModel.time.observeAsState(0L)
    LaunchedEffect(key1 = time ){
        delay(1000L)
        timeViewModel.onTimeChange(time + 1)
    }
    val dec = DecimalFormat("00")
    val min = time / 60
    val sec = time % 60
    Text(
        modifier = Modifier.wrapContentSize(),
        text = "${dec.format(min)}:${dec.format(sec)}",
        style = MaterialTheme.typography.body1
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 00:06:04