0

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

1) 打开应用程序,主活动显示默认共享首选项中的 foo 值 = 1

2)进入设置

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

4) 输入值 3

5) 使用 Ok 按钮关闭我的 DialogPreference

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

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

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

7) 取消对话框

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

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

9) 进入设置

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

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

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

我的对话首选项

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 来工作?

首选项.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>
4

2 回答 2

1

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

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

于 2018-09-27T16:20:57.997 回答
0

在某些时候,我总觉得我在破解 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 的同时,我以全新的思维解决了这个问题,并利用我确定对话框正在获取首选项键这一事实,我使用此修复程序来解决问题,它运行良好。

我将这行代码添加到 onBindDialogView 的开头

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

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

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

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

这通常很简单,在我检查的所有其他内容中,我错过了那个小小的变化。

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

于 2018-09-28T12:57:15.260 回答