避免 Androids SharedPreferences 中的默认值

问题描述

SharedPreferences 提供以下函数来检索字符串:

String getString(String key,@Nullable String defValue);

存储 Int 时,认值不可为空:

int getInt(String key,int defValue);

我现在想要存储和检索一个可为空的 Int?,例如:

var timerDuration: Int?
    get() = prefs.getIntOrNull(TIMER_DURATION)
    set(value) { prefs.edit { putIntOrNull(TIMER_DURATION,value) } }

方案一:当value为null时,去掉key

private fun SharedPreferences.getIntOrNull(key: String) =
    if (prefs.contains(key)) {
        getInt(key,12345)
    } else {
        null
    }

private fun SharedPreferences.Editor.putIntOrNull(key: String,value: Int?) =
    if (value == null) {
        remove(key)
    } else {
        putInt(key,value)
    }

...但我不确定我是否会因为共享首选项的异步性质而遇到多次快速访问的问题?


解决方案 2:对所有内容使用字符串选项:

private fun SharedPreferences.getIntOrNull(key: String) =
    prefs.getString(key,null)?.toIntOrNull()

private fun SharedPreferences.Editor.putIntOrNull(key: String,value: Int?) =
    putString(key,value?.toString())

...但是对于这样一个简单的任务来说,.toIntOrNull() 感觉开销很大吗?


我为什么要这样做?

我希望 Kotlin Multiplattform 允许我将 iOS 版本添加到我现有的 Android 应用程序中。 我的目标是完全用 Kotlin 编写的“核心”模块,没有特定于平台的依赖项。 然后“核心”只使用这个接口,由 Android & iOS 实现 - Apps

interface Settingsstorage {

    var timerDuration: Int?

    [...]
}

因为我不想有重复的认值逻辑,所以我很乐意在我的“核心”模块中处理它


还有其他(更好的)选择吗?我感觉我在重新发明轮子...

解决方法

你的任何一种方法都可以。 SharedPreferences 是线程安全的。如果您将清单中的服务设置为在单独的进程中运行,并且它与应用程序的其余部分同时修改首选项,则选项 1 才会真正失败。这不是你会不小心做的事情。

你的第二个方法没有任何额外的开销,因为在引擎盖下,SharedPreferences 都是字符串,所以你的代码基本上和 SharedPreferences.getInt 做同样的事情,除了当首选项没有时返回默认值存在或无法解析为 Int。

,

当您将 Int 存储到 SharedPreferences 时,它在内部存储为字符串。因此,对于获取,只需获取一个字符串,如果它是 null 则返回它,或者尝试将其解析为 Int。对于设置,只需将您的 Int 转换为 String 并使用 putString 方法将其放置。

var timerDuration: Int?
    get() = try { prefs.getString(TIMER_DURATION,null)?.toInt() } catch (e: Exception) { null }
    set(value) { prefs.edit { putString(TIMER_DURATION,value.toString()) } }