Android 使用Preferences DataStore替代SharedPreferences

1,063 阅读2分钟

在开发过程中经常会遇到需要在本地存储轻量数据,以往都是通过SharedPreferences来实现,但现在官方推荐使用DataStore来替代。

本篇文章介绍下如何使用Preferences DataStore来替代SharedPreferences。

DataStore简介

DataStore是一种数据存储解决方案,使用Kotlin协程和Flow以异步、一致的事务方式来存储数据。分为:

  • Preferences DataStore:类似SharedPreferences,采用键值对的方式来存储数据。
  • Proto DataStore:将数据作为自定义数据类型的实例进行存储。

Preferences DataStore

1.在项目中引入Preferences DataStore

在项目app module的build.gradle中的defaultConfig中添加依赖:

    implementation("androidx.datastore:datastore-preferences:1.0.0")
 
    //如果使用Rxjava
    //Rxjava2的支持
    implementation("androidx.datastore:datastore-preferences-rxjava2:1.0.0")
    //Rxjava3的支持
    implementation("androidx.datastore:datastore-preferences-rxjava3:1.0.0")

如果有开启混淆,则还需要在混淆文件中添加:

-keepclassmembers class * extends androidx.datastore.preferences.protobuf.GeneratedMessageLite {
    <fields>;
}

2.Preferences DataStore的使用

  1. 创建Preferences DataStore 使用由preferencesDataStore创建的属性委托来创建实例。创建后,就可以在应用内通过context.dataStore来访问该实例。
    val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "StoreName")
  1. 存取数据 存取数据之前,需要使用键类型函数为值定义一个键。键类型函数包括:
  • intPreferencesKey(name: String)
  • doublePreferencesKey(name: String)
  • stringPreferencesKey(name: String)
  • booleanPreferencesKey(name: String)
  • floatPreferencesKey(name: String)
  • longPreferencesKey(name: String)
  • stringSetPreferencesKey(name: String)

接下来使用intPreferencesKey介绍一下如何存取数据。

class TestActivity: Activity() {

    val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "StoreName")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_test_activity)
        
        //存数据
        lifecycleScope.launch{
            saveIntValue(this@TestActivity, "TestInt", 100)
        }
        
        //取数据
        val btnGetValue = findViewById<Button>(R.id.get_value)
        btnGetValue.setOnClickListener {
           lifecycleScope.launch{
               val intValue = getIntValue(this@TestActivity, "TestInt",0)
               Log.e("test", "get int value:$intValue")
           }
        }
    }
    
    suspend fun saveIntValue(context: Context, keyName: String, value: Int) {
        val key = intPreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getIntValue(context: Context, keyName: String, defaultValue: Int? = null): Int {
        val key = intPreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: 0)
        }.first()
    }
}

Preferences DataStore的工具类

针对Preferences DataStore进行了简单的封装便于使用,代码如下:

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map

class DataStorePreferencesHelper private constructor(var storeName: String? = null) {

    private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = storeName
        ?: "MiniGamePreferencesDataStore")

    companion object {
        @Volatile
        private var dataStorePreferencesHelper: DataStorePreferencesHelper? = null

        fun getInstance(storeName: String? = null): DataStorePreferencesHelper {
            if (dataStorePreferencesHelper == null) {
                synchronized(DataStorePreferencesHelper::class.java) {
                    if (dataStorePreferencesHelper == null) {
                        dataStorePreferencesHelper = DataStorePreferencesHelper(storeName)
                    }
                }
            }
            return dataStorePreferencesHelper!!
        }
    }

    suspend fun saveIntValue(context: Context, keyName: String, value: Int) {
        val key = intPreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getIntValue(context: Context, keyName: String, defaultValue: Int? = null): Int {
        val key = intPreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: 0)
        }.first()
    }

    suspend fun saveLongValue(context: Context, keyName: String, value: Long) {
        val key = longPreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getLongValue(context: Context, keyName: String, defaultValue: Long? = null): Long {
        val key = longPreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: 0L)
        }.first()
    }

    suspend fun saveFloatValue(context: Context, keyName: String, value: Float) {
        val key = floatPreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getFloatValue(context: Context, keyName: String, defaultValue: Float? = null): Float {
        val key = floatPreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: 0f)
        }.first()
    }

    suspend fun saveDoubleValue(context: Context, keyName: String, value: Double) {
        val key = doublePreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getDoubleValue(context: Context, keyName: String, defaultValue: Double? = null): Double {
        val key = doublePreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: 0.0)
        }.first()
    }

    suspend fun saveBooleanValue(context: Context, keyName: String, value: Boolean) {
        val key = booleanPreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getBooleanValue(context: Context, keyName: String, defaultValue: Boolean? = null): Boolean {
        val key = booleanPreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: false)
        }.first()
    }

    suspend fun saveStringValue(context: Context, keyName: String, value: String) {
        val key = stringPreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getStringValue(context: Context, keyName: String, defaultValue: String? = null): String {
        val key = stringPreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: "")
        }.first()
    }

    suspend fun saveStringSetValue(context: Context, keyName: String, value: Set<String>) {
        val key = stringSetPreferencesKey(keyName)
        context.dataStore.edit {
            it[key] = value
        }
    }

    suspend fun getStringSetValue(context: Context, keyName: String, defaultValue: Set<String>? = null): Set<String> {
        val key = stringSetPreferencesKey(keyName)
        return context.dataStore.data.map {
            it[key] ?: (defaultValue ?: setOf())
        }.first()
    }

}