Android jetpack-DataStore

1.DataStore

DataStore出现之前,用的最多的存储方式就是SharedPreferences,它的使用方式简单。然而google对SP的定义为轻量级存储,如果存储的数据少,使用起来没有任何问题,当需要存储数据比较多时,SP可能会导致以下问题:

①SP第一次加载数据时需要全量加载,当数据量大时可能会阻塞UI线程造成卡顿。

②SP读写文件不是类型安全的,且没有发出错误信号的机制,缺少事务性API。

③commit() / apply()操作可能会造成ANR问题:

commit()是同步提交,会在UI主线程中直接执行IO操作,当写入操作耗时比较长时就会导致UI线程被阻塞,进而产生ANR;apply()虽然是异步提交,但异步写入磁盘时,如果执行了Activity / Service中的onStop()方法,那么一样会同步等待SP写入完毕,等待时间过长时也会引起ANR问题。

为了避免SP的这些问题,可以是使用DataStore来优化。DataStore是一种改进的新数据存储解决方案,允许使用协议缓冲区存储键值对或类型化对象。DataStore以异步、一致的事务方式存储数据,克服了SharedPreferences的一些缺点。DataStore基于Kotlin协程和Flow实现,并且可以对SP数据进行迁移,旨在取代SP。

DataStore提供了两种不同的实现:Preferences DataStore与Proto DataStore,其中Preferences DataStore用于存储键值对;Proto DataStore用于存储类型化对象。

DataStore的优势:

①DataStore基于事务方式处理数据更新。

②DataStore基于Kotlin Flow存取数据,默认在Dispatchers.IO里异步操作,避免阻塞UI线程,且在读取数据时能对发生的Exception进行处理。

③不提供apply()、commit()存留数据的方法。

④支持SP一次性自动迁移至DataStore中。

2.DataStore用法

DataStore用Kotlin语言时用法很简单,参考官网即可;对于java语言,如果不用RxJava,很难构建出DataStore对象,所以,这里使用RxJava。

①添加依赖项

implementation 'androidx.datastore:datastore-preferences:1.0.0' 

implementation 'androidx.datastore:datastore-rxjava3:1.0.0' 

implementation 'androidx.datastore:datastore-preferences-rxjava3:1.0.0' 

②构建Preferences DataStore

RxDataStore<Preferences> dataStore = new RxPreferenceDataStoreBuilder(context, "pf_datastore").build();

这样就成功创建了Preferences DataStore,其中pf_datastore是创建Preferences DataStore的文件名称。

上述代码执行后,会在/data/data/包名/files/下创建名为pf_datastore的文件如下:

26975cde254c47b79a0992f7ac512afa.jpg

可以看到后缀名并不是xml,而是.preferences_pb。

③存数据

dataStore.updateDataAsync(prefsIn -> {

    MutablePreferences mutablePreferences = prefsIn.toMutablePreferences();

    MutablePreferences.set( PreferencesKeys.intKey("my_key"), 5);

    return Single.just(mutablePreferences);

});

这样就将数字5存进了名为pf_datastore的文件里对应key为my_key的字段里。

④取数据

Preferences.Key<Integer> myKey = PreferencesKeys.intKey("my_key");

Flowable<Integer> myValueFlow = datastore.data().map(prefs -> prefs.get(myKey);

myValueFlow.subscribeOn(Schedulers.io()).subscribe(

    @override

    public void accept(Integer integer) throws Throwable {

       Log.i(TAG, "取到的值为:" + integer);

    }

);

通过datastore.data()返回的是Flow数据,后续就可以通过Flow对数据进行一系列处理。从文件读取数据时,如果出现错误,系统会抛出IOExceptions。可以在 map()之前使用catch()运算符,并且在抛出的异常是IOException时发出emptyPreferences()。如果出现其他类型的异常,重新抛出该异常。

注意:Preferences DataStore存取数据时的Key是Preferences.Key< T>类型,且其中的T只能存 Int、Long、Float、Double、Boolean、String、Set< String>类型。如果不是上面的类型,会直接抛异常。

猜你喜欢

转载自blog.csdn.net/zenmela2011/article/details/124837561