【问题标题】:What's the point of having a default value in sharedPref.getString?在 sharedPref.getString 中有一个默认值有什么意义?
【发布时间】:2023-03-09 11:03:01
【问题描述】:

我正在通过 SharedPreferences 访问我的 Android 应用程序

private val sharedPref = PreferenceManager.getDefaultSharedPreferences(context)`

然后尝试使用

从中获取数据
val lat: String = sharedPref.getString("MyKey", "Default")

但是这一行给我一个错误阅读"Type mismatch. Required String, found String?"

根据文档,getString 方法中的第二个参数表示“如果此首选项不存在,则返回值。此值可能为空。

那么,如果该值可以为空,那么有一个默认值有什么意义呢?我似乎无法获得永远使用的默认值,我可以让我的代码工作的唯一方法是使用 elvis 运算符并将我的代码重写为:

val lat: String = sharedPref.getString("MyKey", "Default") ?: "Default"

看起来很丑。我疯了吗?我错过了什么?

【问题讨论】:

    标签: android kotlin sharedpreferences


    【解决方案1】:

    这样考虑: SharedPreferences 中的每个 String 首选项可以existnot,并且可以是nullnot。所以代码

    val lat: String = sharedPref.getString("MyKey", "Default") ?: "Not Set"
    

    将返回:

    • Default 如果此 Key 的首选项不存在(意味着此 Key 没有映射)
    • Not Set 如果首选项存在,但为 null(将 Key 映射到 null 创建)
    • 任何其他value,如果存在首选项并且映射的值不是null

    更新

    显然,SharedPreferences 没有我想象的那么聪明。内部有这段代码:

    String v = (String)mMap.get(key);
    return v != null ? v : defValue;
    

    如果我们将 null 作为默认值(并且没有保存任何值),它将返回 null 。这意味着我们实际上不需要 elvis 选项,并且 我们不会获得 "Not Set" 值。该方法返回可空值,只是因为它允许您将可空值作为默认值传递。

    【讨论】:

    • 您的回复对我来说最有意义。 getInt 和 getLong 不能为 null 但 getString 可以 对我来说似乎很奇怪
    • 那是因为getIntgetLong等在Java中使用原始类型,所以它们不能是null
    • 这不是正确的答案,它返回默认值,即使它以前从未用这样的键保存过。
    • @NurseyitTursunkulov, "它以前从未使用这样的键保存过" = 此键没有映射 -> 返回默认值。
    • @Demigod 我们永远不会为空
    【解决方案2】:

    这是因为在阅读以下代码时启动了 kotlin Null-Safety:

    val lat: String = sharedPref.getString("MyKey", "Default")
    

    如果你访问SharedPreferences代码,你可以看到following code

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

    这给了我们使用 null 作为defValue 参数的概率。所以,Kotlin 尝试保护它并给你匹配错误:

    “类型不匹配。必需的字符串,找到字符串?”

    您可以通过以下方式为您的 String 变量启用 nullable 来解决此问题:

    val lat: String? = sharedPref.getString("MyKey", "Default")
    

    虽然这反对Kotlin type system purpose:

    Kotlin 的类型系统旨在消除代码中空引用的危险,也称为“十亿美元错误”。

    【讨论】:

    • 感谢您的回复,我了解如何解决该问题,但作为开发人员,我试图解决数十亿美元的错误,是将代码中可空变量的数量保持在最低限度。 getInt 和 getLong 不能为空,为什么 getString 可以呢?
    • 这是因为int getInt(String key, int defValue);long getLong(String key, long defValue); 都没有可以为空的默认值参数。您可以在android.googlesource.com/platform/frameworks/base/+/3e7d977/… 看到。请注意,Android 的 kotlin 依赖于 Java 中的 Android api。因此,Android 版 kotlin 不会完全避免 null。
    【解决方案3】:

    SharedPreferences 是 Google 提供的对 Key/Value 数据库的抽象,您如何使用它取决于您。如果您不喜欢这种语法,请为您的getString() 创建一个包装器或扩展程序。举个例子:

    fun PreferenceManager.getStringTheFancyWay(key: String, defaultValue: String): String {
        return getString(key, defaultValue) ?: defaultValue
    }
    val value = getStringTheFancyWay("a", "b")
    

    我个人不喜欢这个,因为null 可以更好地控制不存在的键。

    这就是我使用 SharedPreferences 的方式

    val preferences = PreferenceManager.getDefaultSharedPreferences(context)
    val value = preferences.getString("username", null)
    if (value != null) {
        toast("Hello $value")
    } else {
        toast("Username not found")
    }
    

    preferences.getString("username", null)?.let { username ->
        toast("Hello $username")
    }
    

    注意到区别了吗?

    【讨论】:

      【解决方案4】:

      事实很简单,想象一下您没有保存任何关于该键的值(对于您的案例“MyKey”)并尝试获取该键的值(对于您的案例“MyKey”)。 SharedPreference 会返回什么?它只会返回默认值。

      您将看到,对于 String 类型,您必须将 null 或任何其他字符串指定为默认值,对于整数类型,您必须将 0 或任何其他 int 值指定为默认值,而对于 bolean 类型,您必须指定 true 或 false 默认值。我希望你能得到答案。

      【讨论】:

        猜你喜欢
        • 2010-10-23
        • 1970-01-01
        • 2017-01-11
        • 1970-01-01
        • 2018-07-17
        • 2019-02-04
        • 2017-01-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多