【问题标题】:DialogPreference is not saving the preference when I expect it to?DialogPreference 没有在我期望的时候保存首选项?
【发布时间】:2018-09-27 15:32:22
【问题描述】:

我编写了一个基本的标准 DialogPreference,它工作正常,除了它没有在我期望的时候将首选项保存到默认共享首选项。

1) 打开应用,主活动显示默认共享偏好设置中的 foo 值 = 1

2) 进入设置

3) 点击 foo 设置打开我的 DialogPreference 并显示 value = 1

4) 输入值 3

5) 使用确定按钮关闭我的 DialogPreference

***** 默认共享首选项 foo 现在应该是 3

6) 点击 foo 设置打开我的 DialogPreference 并显示 value = 1

***** 所以我的 DialogPreference 没有将首选项保存到默认共享首选项?

7) 取消对话框

8) 返回主活动,显示默认共享首选项中 foo 的值 = 3

***** 所以我的 DialogPreference 确实将首选项保存到默认共享首选项

9) 进入设置

10) 点击 foo 设置打开我的 DialogPreference 并显示值为 3

为什么在第 (6) 步默认共享首选项的值不是 foo = 3?

似乎只有当流程从设置列表返回到主活动时才会将首选项保存到默认共享首选项中,这与将首选项保存在 DialogPreference 的 onDialogClosed 方法中是反直觉的。

MyDialogPreference

public class MyDialogPreference extends DialogPreference
{
private static final String DEFAULT_VALUE = "0";
private String value = DEFAULT_VALUE;
private EditText editText;

public MyDialogPreference(Context context, AttributeSet attrs)
{
    super(context, attrs);
    setDialogLayoutResource(R.layout.constrained_integer_preference);
}

@Override
public void onBindDialogView(View view)
{
    super.onBindDialogView(view);

    editText = (EditText) view.findViewById(R.id.edit);
    editText.setText("" + value);
}

@Override
protected void onDialogClosed(boolean positiveResult)
{

    if (positiveResult)
    {
        persistString(editText.getText().toString());
    }

    super.onDialogClosed(positiveResult);
}

@Override
protected Object onGetDefaultValue(TypedArray typedArray, int index)
{
    return typedArray.getString(index);
}

@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue)
{

    if (restorePersistedValue)
    {
        value = getPersistedString(DEFAULT_VALUE);
    }
    else
    {
        value = (String) defaultValue;

        if (shouldPersist())
        {
            persistString(value);
        }

    }

}

}

编辑: 因此,我使用 DialogPreference 处理的首选项似乎没有键,这导致了所有问题。但是我已经在preferences.xml 文件中为这个DialogPreference 指定了键。我已尽一切努力强制识别密钥,但没有任何效果。

谁能告诉我如何让 DialogPreference 从preferences.xml 文件中接收 android:key 来工作?

preferences.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<org.mycompany.myproject.MyDialogPreference
    android:defaultValue="11"
    android:dialogLayout="@layout/my_preference"
    android:inputType="number"
    android:key="MY_KEY"
    android:selectAllOnFocus="true"
    android:singleLine="true"
    android:summary="summary"
    android:title="My Preference" />
</PreferenceScreen>

【问题讨论】:

  • 对不起厚了,什么意思?

标签: android sharedpreferences dialog-preference


【解决方案1】:

您必须实现OnPreferenceChangeListener 和/或调用notifyChanged()

除非您提供 DialogPreference 的代码,否则很难重现该问题。

【讨论】:

  • 我之前无法添加我的代码,但现在将其添加到我的问题中。我尝试使用更改侦听器,但没有被调用。
  • developer.android.com/reference/android/preference/… ...可能会解释为什么不会触发该侦听器。
  • 并非如此。我可以很好地自定义 EditTextPreference,但在这种情况下,我必须执行一个对话框,并且仍然无法在设置列表中保存首选项,这对于我之前所做的任何 EditTextPreference 自定义都不会发生.我已经审查了我在其中所做的事情,但它并没有为我清除任何东西。
  • 它清楚地读作EditText ...显然不是EditTextPreference
  • 您提供的链接是针对 EditTextPreference 而不是 EditText
【解决方案2】:

在某些时候,我总觉得我在破解 Android,这绝对是一个 hack。

最初我认为我要解决的问题是框架忽略了我的 android:key,因为 getKey() 返回一个空字符串,但事实并非如此,因为它在启动 PreferenceScreen 时会获取持久值,并且当我关闭 DialogPreference 时,将更改的值保存到共享首选项。

所以看来我要解决的问题是框架将首选项持久值读入内部成员,然后使用内部成员直到流程从首选项框架返回,而在 DialogPreference 关闭后不刷新它们。

但我终于找到了一种让 PreferenceScreen 刷新它在其内部成员中保存的首选项持久值的方法。虽然它不是真正的刷新,但它是一个 hack。

所以我所做的基本上就是扔掉 PreferenceScreen 并创建一个新的。为此,我在 addPreferencesFromResource(R.xml.preferences) 之前直接将以下代码添加到我的 SettingsFragment.onCreate 方法中。

    SharedPreferences.OnSharedPreferenceChangeListener prefListener = (prefs, key) ->
    {
        setPreferenceScreen(null);
        addPreferencesFromResource(R.xml.preferences);
    };

    PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()).registerOnSharedPreferenceChangeListener(prefListener);

这可能很糟糕。我已经反复测试过它,虽然不是很彻底,到目前为止还没有看到任何不利影响。

因此,有了这个 hack,我现在可以从 PreferenceScreen 重复打开一个 DialogPreference,保存一个新值,然后使用之前更新的值返回到 DialogPreference。

我不相信我的 hack 是实现这一结果的预期方式,但是在搜索源代码和谷歌几天后,我没有找到任何其他东西。

我把这个答案留给其他面临同样问题并且有足够勇气尝试我的破解的人。如果(可能何时)我发现黑客有任何问题,我会更新答案。

更好的是,如果其他人可以提供首选解决方案,并指出我做错了什么导致问题,请这样做。

编辑:在工作了这么久之后,这个 hack 最终还是失败了,并且始终如一。

但在删除 hack 的同时,我以全新的思维解决了这个问题,并利用我确定对话框正在获取首选项键这一事实,我使用此修复程序来解决问题,它运行良好。

我在onBindDialogView的开头添加了这行代码

value = getSharedPreferences().getString(getKey(), "-1");

这使得对 onGetDefaultValue 和 onSetInitialValue 的调用变得多余,但它们并没有按预期工作,至少对我来说不是。

编辑: 天哪,我讨厌这个!

我没有注意到在之前的重构过程中,更新 onDialogClosed 中 DialogPreference 内部值的代码行被删除了。

这通常很简单,但我检查了所有其他内容,但我错过了那个小改动。

我只是在对 repo 进行代码审查时才注意到它,现在我觉得很傻。所以最终不需要额外的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多