Android 使用DataStore存储数据
2021-02-19 本文已影响0人
Afra55
- 1 添加依赖
- 2 在 main 文件夹下创建 .proto 文件
- 3 编写 Serializer
- 4 编写基础存储工具类
- 5 举例使用
** 5.1 创建 DataStore 存储工具子类
** 5.2 基本使用 - 6 混淆
0 使用 SharedPreferences 保存数据
0.1 创建SP Base 类
open class BaseSp(val name: String = "Clear") {
private var sp: SharedPreferences? =
AppApplication.context?.getSharedPreferences(name, Context.MODE_PRIVATE)
fun setValue(key: String, any: Any) {
sp?.let {
val edit = it.edit()
when (any) {
is String -> edit.putString(key, any)
is Boolean -> edit.putBoolean(key, any)
is Int -> edit.putInt(key, any)
is Long -> edit.putLong(key, any)
is Float -> edit.putFloat(key, any)
else -> {
edit.putString(key, any.toString())
}
}
edit.apply()
}
}
fun getBooleanValue(key: String, default: Boolean): Boolean {
return sp?.getBoolean(key, default) ?: default
}
fun getStringValue(key: String, default: String? = ""): String? {
return sp?.getString(key, default) ?: default
}
fun getIntValue(key: String, default: Int): Int {
return sp?.getInt(key, default) ?: default
}
fun getLongValue(key: String, default: Long): Long {
return sp?.getLong(key, default) ?: default
}
fun getFloatValue(key: String, default: Float): Float {
return sp?.getFloat(key, default) ?: default
}
fun clearAll() {
sp?.edit()?.clear()?.apply()
}
}
0.2 继承SP Base 实现自己的 sp 文件
object MySp : BaseSp("可选sp名") {
...
}
1 添加依赖
implementation "androidx.datastore:datastore:1.0.0-alpha06"
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha06"
implementation "com.google.protobuf:protobuf-java:3.15.0"
2 在 main 文件夹下创建 .proto
文件
![](https://img.haomeiwen.com/i10733883/7eb1488ae32ff253.png)
syntax = "proto3";
option java_package = "com.afra55.xxx.ds.event";
option java_multiple_files = true;
message MessageEvent {
int32 type = 1;
string message = 2;
}
根据不同的存储需求来实现不同的 proto 文件,然后进行编译, java_package 是生成文件的路径
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/ds.proto
例如当在 proto 文件夹下:
protoc -I=. --java_out=../java ./ds.proto
许多标准的简单数据类型都可以作为字段类型,包括bool,int32,float,double,和string。
![](https://img.haomeiwen.com/i10733883/7bd9975d6b0463fe.png)
protoc 命令下载地址:
https://github.com/protocolbuffers/protobuf/releases
3 编写 Serializer
object MessageEventSerializer :Serializer<MessageEvent>{
override val defaultValue: MessageEvent
get() = MessageEvent.getDefaultInstance()
override fun readFrom(input: InputStream): MessageEvent {
try {
return MessageEvent.parseFrom(input)
} catch (e: Exception) {
throw CorruptionException("Cannot read proto.", e)
}
}
override fun writeTo(t: MessageEvent, output: OutputStream) {
t.writeTo(output)
}
}
4 编写基础存储工具类
import androidx.datastore.core.DataStore
import androidx.datastore.createDataStore
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.createDataStore
import androidx.datastore.createDataStore
import com.afra55.thunderomadtestapplication.AppApplication
import com.afra55.thunderomadtestapplication.ds.event.MessageEvent
import com.afra55.thunderomadtestapplication.toJsonString
import com.afra55.thunderomadtestapplication.toObject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlin.reflect.KClass
/**
* @author Afra55
* @date 2/18/21
* A smile is the best business card.
*
* 需要添加混淆:
-keepclassmembers class * extends androidx.datastore.preferences.protobuf.GeneratedMessageLite {
<fields>;
}
*/
open class DataStoreBase(name: String) {
val dataStore: DataStore<Preferences>? by lazy {
AppApplication.context?.createDataStore(name)
}
val messageEventDataStore: DataStore<MessageEvent>? by lazy {
AppApplication.context?.createDataStore(
fileName = name,
serializer = MessageEventSerializer
)
}
suspend fun getString(key: String, defaultValue:String? = null):String? {
return dataStore?.data?.map { preferences ->
preferences[stringPreferencesKey(key)] ?: defaultValue
}?.first()
}
suspend fun getInt(key: String, defaultValue:Int? = null): Int? {
return dataStore?.data?.map { preferences ->
preferences[intPreferencesKey(key)] ?: defaultValue
}?.first()
}
suspend fun getDouble(key: String, defaultValue:Double? = null): Double? {
return dataStore?.data?.map { preferences ->
preferences[doublePreferencesKey(key)] ?: defaultValue
}?.first()
}
suspend fun getBoolean(key: String, defaultValue:Boolean? = null): Boolean? {
return dataStore?.data?.map { preferences ->
preferences[booleanPreferencesKey(key)] ?: defaultValue
}?.first()
}
suspend fun getFloat(key: String, defaultValue:Float? = null): Float? {
return dataStore?.data?.map { preferences ->
preferences[floatPreferencesKey(key)] ?: defaultValue
}?.first()
}
suspend fun getLong(key: String, defaultValue:Long? = null): Long? {
return dataStore?.data?.map { preferences ->
preferences[longPreferencesKey(key)] ?: defaultValue
}?.first()
}
suspend fun getStringSet(key: String, defaultValue:Set<String>? = null): Set<String>? {
return dataStore?.data?.map { preferences ->
preferences[stringSetPreferencesKey(key)] ?: defaultValue
}?.first()
}
suspend fun <T> getObject(key: String, clazz: Class<T>, defaultValue:T? = null): T? {
return dataStore?.data?.map { preferences ->
val a = preferences[stringPreferencesKey(key)]
if (a != null) {
a.toObject(clazz) as T
} else {
defaultValue
}
}?.first()
}
suspend fun <T : Any> get(key: String, clazz: KClass<T>, defaultValue: T? = null): T? {
val pKey = when (clazz) {
String::class -> {
stringPreferencesKey(key)
}
Int::class -> {
intPreferencesKey(key)
}
Double::class -> {
doublePreferencesKey(key)
}
Boolean::class -> {
booleanPreferencesKey(key)
}
Float::class -> {
floatPreferencesKey(key)
}
Long::class -> {
longPreferencesKey(key)
}
Set::class -> {
stringSetPreferencesKey(key)
}
else -> {
null
}
}
return dataStore?.data?.map { preferences ->
if (pKey != null) {
(preferences[pKey] as? T) ?: defaultValue
} else {
val a = preferences[stringPreferencesKey(key)]
if (a != null) {
a.toObject(clazz::class.java) as T
} else {
defaultValue
}
}
}?.first()
}
suspend fun put(key: String, value: Any) {
when (value::class) {
String::class -> {
dataStore?.edit { settings ->
settings[stringPreferencesKey(key)] = value as String
}
}
Int::class -> {
dataStore?.edit { settings ->
settings[intPreferencesKey(key)] = value as Int
}
}
Double::class -> {
dataStore?.edit { settings ->
settings[doublePreferencesKey(key)] = value as Double
}
}
Boolean::class -> {
dataStore?.edit { settings ->
settings[booleanPreferencesKey(key)] = value as Boolean
}
}
Float::class -> {
dataStore?.edit { settings ->
settings[floatPreferencesKey(key)] = value as Float
}
}
Long::class -> {
dataStore?.edit { settings ->
settings[longPreferencesKey(key)] = value as Long
}
}
Set::class -> {
dataStore?.edit { settings ->
settings[stringSetPreferencesKey(key)] = value as Set<String>
}
}
else -> {
dataStore?.edit { settings ->
settings[stringPreferencesKey(key)] = value.toJsonString()
}
}
}
}
suspend fun getMessageEventType():Int? {
return messageEventDataStore?.data?.map {
it.type
}?.first()
}
suspend fun getMessageEventData():String? {
return messageEventDataStore?.data?.map {
it.message
}?.first()
}
suspend fun getMessageEvent():MessageEvent? {
return messageEventDataStore?.data?.map {
it
}?.first()
}
suspend fun putMessageEvent(message:String) {
messageEventDataStore?.updateData {
it.toBuilder()
.setType(it.type)
.setMessage(message)
.build()
}
}
suspend fun putMessageEvent(type:Int) {
messageEventDataStore?.updateData {
it.toBuilder()
.setType(type)
.setMessage(it.message)
.build()
}
}
suspend fun putMessageEvent(type:Int, message:String) {
messageEventDataStore?.updateData {
it.toBuilder()
.setType(type)
.setMessage(message)
.build()
}
}
}
5 举例使用
5.1 创建 DataStore 存储工具子类
object IPDataStore :DataStoreBase("ip"){
}
5.2 基本使用
lifecycleScope.launch {
Log.i("ip", IPDataStore.getString("ip")?:"null")
Log.i("message_event", IPDataStore.getMessageEventType().toString())
Log.i("message_event", IPDataStore.getMessageEventData().toString())
val r = withContext(Dispatchers.IO){
try {
runHttp("http://ip-api.com/json")
} catch (e: Exception) {
e.printStackTrace()
}
}
if (r is String) {
IPDataStore.put("ip", r)
IPDataStore.putMessageEvent(12, r)
IPDataStore.getString("ip")?.let {
Log.i("ip", it?:"null")
}
}
Log.i("message_event", IPDataStore.getMessageEventType().toString())
Log.i("message_event", IPDataStore.getMessageEventData().toString())
IPDataStore.getMessageEvent()?.let {
Log.i("message_event", it.toString())
}
Log.i("ip", "获取完成")
}
var client = OkHttpClient()
fun runHttp(url: String): String? {
val request: Request = Request.Builder()
.url(url)
.build()
client.newCall(request).execute().use { response -> return response.body!!.string() }
}
6 混淆
-keepclassmembers class * extends androidx.datastore.preferences.protobuf.GeneratedMessageLite {
<fields>;
}