在 Kotlin 中使用 "androidx.preference:preference-ktx:1.1.1" 时如何读写 SharedPreferences?

How to read and write SharedPreferences when use "androidx.preference:preference-ktx:1.1.1" with Kotlin?

通常,我使用代码A或代码B来读取或写入SharedPreferences。

目前,我更新我的项目以使用 "androidx.preference:preference-ktx:1.1.1" 和 Kotlin。

当我使用 "androidx.preference:preference-ktx:1.1.1" 和 Kotlin 时,是否有更好的读写 SharedPreferences 的方法?

代码A

SharedPreferences prfs = getSharedPreferences("AUTHENTICATION_FILE_NAME", Context.MODE_PRIVATE);
String Astatus = prfs.getString("Authentication_Status", "");

代码B

SharedPreferences preferences = getSharedPreferences("AUTHENTICATION_FILE_NAME", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("Authentication_Id",userid.getText().toString());
editor.putString("Authentication_Password",password.getText().toString());
editor.putString("Authentication_Status","true");
editor.apply();

在您的 Pref.class 文件中为构造函数提供上下文。

    class Prefs constructor(
            private val context: Context
        ) {
    
       private fun getSharedPreferences(prefsName: String) =
            context.getSharedPreferences(prefsName, Context.MODE_PRIVATE)
    
        private val AUTH_PHONE = "auth_phone"
        private val KEY_AUTH_PHONE = "auth_phone"
        private val authPhone by lazy { getSharedPreferences(AUTH_PHONE) }
        
        var phoneNumber: String
            get() {
                return authPhone.getString(KEY_AUTH_PHONE, null) ?: return ""
            }
            set(value) {
                authPhone.edit()
                    .putString(KEY_AUTH_PHONE, value)
                    .apply()
            } 
}

然后你就可以在你的 activity 中使用它了。

  Pref(context).phoneNumber = "998998578086"

如果你没有使用hiltkoin等依赖注入工具,最好做一个单例class 它管理首选项值,以便在每次要读取或写入值时不获取 SharedPreferences 对象。 帮助您以线程安全的方式创建带有参数的单例 class。

否则,如果您在项目中使用依赖注入工具,则可以跳过以下解决方案的单例部分,让 DI 工具来完成。


PrefManager.kt

import android.content.Context

class PrefManager private constructor(context: Context) {

    // ------- Preference Variables

    var authenticationId: String?
        get() = pref.getString("KEY_AUTHENTICATION_ID", null)
        set(value) = pref.edit { putString("KEY_AUTHENTICATION_ID", value) }

    var authenticationStatus: Boolean
        get() = pref.getBoolean("KEY_AUTHENTICATION_STATUS", false)
        set(value) = pref.edit { putBoolean("KEY_AUTHENTICATION_STATUS", value) }

    // ---------------------------------------------------------------------------------------------

    private val pref = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)

    fun clear() = pref.edit { clear() }

    companion object : SingletonHolder<PrefManager, Context>(::PrefManager) {
        private const val FILE_NAME = "AUTHENTICATION_FILE_NAME"
    }
}

SingletonHolder.kt

open class SingletonHolder<out T, in A>(private val constructor: (A) -> T) {

    @Volatile
    private var instance: T? = null

    fun getInstance(arg: A): T {
        return when {
            instance != null -> instance!!
            else -> synchronized(this) {
                if (instance == null) instance = constructor(arg)
                instance!!
            }
        }
    }
}

用法:

现在我们可以读取如下值:

val authenticationId = PrefManager.getInstance(context).authenticationId

为了写:

PrefManager.getInstance(context).authenticationId = "SOME VALUE"

无需编写自己的额外代码,对于您的代码 B 片段,您可以使用 ktx 库完成此操作

val preferences = getSharedPreferences("AUTHENTICATION_FILE_NAME", MODE_PRIVATE)
preferences.edit {
   putString("Authentication_Id", userid.getText().toString())
   putString("Authentication_Password", password.getText().toString())
   putString("Authentication_Status", "true")
}

如果您想更进一步并提高安全性,可以并行使用 encrypted sharedPreferences,因为它仅适用于 Android M 及以上。如果你使用 DI,这真的很容易:

interface SharedPrefs {
    var accessToken: String?
    fun get(): SharedPreferences
}

class SimplePreferences(context: Context) : SharedPrefs {
    private val preferences: SharedPreferences =
        context.getSharedPreferences("myapp_preferences", Context.MODE_PRIVATE)

    override fun get(): SharedPreferences = preferences

    override var accessToken: String?
        get() = preferences.getString(MyApp.ACCESS_TOKEN_PREF_KEY, null)
        set(value) = preferences.edit().putString(MyApp.ACCESS_TOKEN_PREF_KEY, value)
            .apply()
}

@TargetApi(Build.VERSION_CODES.M)
class EncryptedSharedPrefs(val context: Context) : SharedPrefs {

    private var encryptedPrefs: SharedPreferences = EncryptedSharedPreferences.create(
        context,
        "myapp_encrypted_prefs",
        MasterKey.Builder(context).build(),
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

    override fun get(): SharedPreferences = encryptedPrefs

    override var accessToken: String?
        get() = encryptedPrefs.getString(MyApp.ACCESS_TOKEN_PREF_KEY, null)
        set(value) = encryptedPrefs.edit().putString(
            MyApp.ACCESS_TOKEN_PREF_KEY,
            value
        ).apply()
}

对币模块:

single {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
         EncryptedSharedPrefs(applicationContext)
   } else
         SimplePreferences(applicationContext)
   }
}

用法:

val sharedPrefs by inject<SharedPrefs>()

// read 
println(sharedPrefs.accessToken)

// write
sharedPrefs.accessToken = "qwerty"