Jetpack DataStore 是一种数据存储解决方案,主要适用于小型数据的处理。它可以通过协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。DataStore有两种实现方式(1)Preferences DataStore 和 (2)Proto DataStore.
Preferences DataStore利用键值对实现对简单数据的读写存储。这种方式不需要预定架构,也不确保类型安全。
要使用Preferences DataStore需要在项目模块的build.gradle.kt中增加如下的依赖库:
dependencies {
...
implementation("androidx.datastore:datastore-preferences:1.0.0")
// 可选项-用于RxJava2支持
implementation("androidx.datastore:datastore-preferences-rxjava2:1.0.0")
// 可选项-用于 RxJava3 支持
implementation("androidx.datastore:datastore-preferences-rxjava3:1.0.0")
}
下面通过一个简单的实例来了解Perference DataStore的应用。在这个例子中, 记录当前账号访问的次数。运行效果如下图所示。
利用该实用类DatastoreUtils实现对数据的读写操作。
class DataStoreUtils(val context:Context){
//利用preferenceDataStore创建委托来创建Preferences DataStore实例
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name="settings")
//定义关键字email
private val EMAIL = stringPreferencesKey("email")
//定义关键字counter
private val COUNTER = intPreferencesKey("counter")
//设置关键字对应存储的email值保存在Flow中
val emailFlow: Flow<String> = context.dataStore.data.map {
it[EMAIL]?:""
}
//设置关键字对应存储的counter值保存在Flow中
val counterFlow:Flow<Int> = context.dataStore.data.map{
it[COUNTER]?:0
}
/**
* 定义挂起函数
* 设置email账号对应访问应用的次数
*/
suspend fun storeData(email:String){
context.dataStore.edit{settings:MutablePreferences->
val storedEmailValue = settings[EMAIL]?:""
val storedCounterValue = settings[COUNTER]?:0
if(storedEmailValue.isBlank()||storedEmailValue!=email) {
settings[EMAIL] = email
settings[COUNTER]= 1
}else{
settings[COUNTER] = storedCounterValue+1
}
}
}
}
在界面的组合函数MainScreen中调用DatastoreUtils实现对数据的读取操作。代码如下:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(dataStoreUtils: DataStoreUtils,modifier:Modifier = Modifier){
val context = LocalContext.current
var emailInput by remember{mutableStateOf("guest@eyes.com")}
var rememberInput by remember{mutableStateOf(false)}
var content by remember{mutableStateOf("")}
val scope = rememberCoroutineScope()
//读取数据
LaunchedEffect(Unit){
dataStoreUtils.counterFlow.collect{c:Int->
dataStoreUtils.emailFlow.collect{account:String->
content = "账号:${account}访问次数是:${c}次"
}
}
}
Column{
TextField(modifier = Modifier.fillMaxWidth(),
value = emailInput,
onValueChange = {it:String->
emailInput = it
},
label ={Text("输入账号")},
leadingIcon = {
Icon(imageVector = Icons.Filled.Email,contentDescription = "账号")
}
)
Row{
Checkbox(checked = rememberInput, onCheckedChange ={
rememberInput = it
if(rememberInput)
scope.launch {
//写入数据
dataStoreUtils.storeData(emailInput)
}
})
Text("记住账号")
}
if(!emailInput.isBlank())
Text(text = content ,fontSize=20.sp)
}
}
说明:因为在应用中,活动界面中只能有一个Preferences DataStore的活动实例,因此在上述代码中对DataStore处理的DatastoreUtils实用类通过传参传递过来。也可以考虑使用单例模式,在整个应用中只有一个处理DataStore的对象实例。
在主活动中调用主界面。代码如下:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ForCourseTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
MainScreen(DataStoreUtils(this))
}
}
}
}
}
启动应用,可以在Device Explorer中的data->data目录下找到应用包,在它的下级目录files->datastore的settings.preferences_pb文件中保存键值对数据。如下图所示:
图1 模拟器中存放的键值对数据
DataStore
https://developer.android.google.cn/topic/libraries/architecture/datastore?hl=zh-cn