DialogPreference 没有在我期望的时候保存首选项?
DialogPreference is not saving the preference when I expect it to?
我写了一个简单的标准 DialogPreference,它工作正常,除了它没有在我预期的时候将偏好保存到默认共享偏好。
1) 打开应用程序,main activity 显示默认共享首选项中 foo 的值 = 1
2) 转到设置
3) 单击 foo 设置打开我的 DialogPreference 并显示值 = 1
4) 输入值 3
5) 使用确定按钮关闭我的 DialogPreference
***** 默认共享首选项 foo 现在应该是 3
6) 单击 foo 设置打开我的 DialogPreference 并显示值 = 1
***** 所以我的 DialogPreference 没有将首选项保存到默认共享首选项?
7) 取消对话框
8) 返回 main activity 显示默认共享首选项中 foo 的值 = 3
***** 所以我的 DialogPreference 确实将首选项保存到默认共享首选项
9) 转到设置
10) 单击 foo 设置打开我的 DialogPreference 并显示值 3
为什么在步骤 (6) 中默认共享首选项的值不是 foo = 3?
当从设置列表returns流向主要activity时,似乎仅将首选项保存到默认共享首选项,这与在 onDialogClosed 中保存首选项不直观DialogPreference 的方法。
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>
您必须实施 OnPreferenceChangeListener and/or call to notifyChanged()。
除非您提供 DialogPreference
的代码,否则很难重现该问题。
在某些时候,我总觉得自己在黑客攻击 Android,这绝对是黑客攻击。
最初我认为我遇到的问题是框架忽略了我的 android:key,因为 getKey() returns 是一个空字符串,但这不可能是真的,因为它获得了持久性启动 PreferenceScreen 时的值,并在关闭 DialogPreference 时将更改的值保存到共享首选项。
所以看来我正在解决的问题是框架将首选项持久值读入内部成员,然后使用内部成员直到 returns 流出首选项框架,而不刷新它们在 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 是实现此结果的预期方式,但在搜索源代码和 google 寻找答案几天后,我没有找到任何其他东西。
我将把这个答案留给面临同样问题并且有足够勇气尝试我的技巧的其他人。如果(可能是什么时候)我发现黑客有任何问题,我会更新答案。
更好的是,如果其他人可以提供首选解决方案,指出我做错了什么导致了问题,请这样做。
编辑: 工作了这么久之后,那个 hack 最终失败了,而且一直如此。
但是在删除 hack 的同时,我以全新的思路解决了这个问题,并且利用我确定对话框正在获取首选项键这一事实,我使用了这个修复程序来解决这个问题,它工作得很好。
我将这行代码添加到 onBindDialogView 的开头
value = getSharedPreferences().getString(getKey(), "-1");
这使得对 onGetDefaultValue 和 onSetInitialValue 的调用变得多余,但它们并没有按预期工作,至少对我来说是这样。
编辑:
天哪,我讨厌这个!
我没有注意到在较早的重构过程中删除了更新 onDialogClosed 中的 DialogPreference 内部值的代码行。
这通常是一些简单的事情,在我检查的所有其他内容中,我错过了那个小改动。
我只是在 repo 的代码审查中才注意到它,现在我觉得很傻。所以最后不需要额外的代码。
我写了一个简单的标准 DialogPreference,它工作正常,除了它没有在我预期的时候将偏好保存到默认共享偏好。
1) 打开应用程序,main activity 显示默认共享首选项中 foo 的值 = 1
2) 转到设置
3) 单击 foo 设置打开我的 DialogPreference 并显示值 = 1
4) 输入值 3
5) 使用确定按钮关闭我的 DialogPreference
***** 默认共享首选项 foo 现在应该是 3
6) 单击 foo 设置打开我的 DialogPreference 并显示值 = 1
***** 所以我的 DialogPreference 没有将首选项保存到默认共享首选项?
7) 取消对话框
8) 返回 main activity 显示默认共享首选项中 foo 的值 = 3
***** 所以我的 DialogPreference 确实将首选项保存到默认共享首选项
9) 转到设置
10) 单击 foo 设置打开我的 DialogPreference 并显示值 3
为什么在步骤 (6) 中默认共享首选项的值不是 foo = 3?
当从设置列表returns流向主要activity时,似乎仅将首选项保存到默认共享首选项,这与在 onDialogClosed 中保存首选项不直观DialogPreference 的方法。
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>
您必须实施 OnPreferenceChangeListener and/or call to notifyChanged()。
除非您提供 DialogPreference
的代码,否则很难重现该问题。
在某些时候,我总觉得自己在黑客攻击 Android,这绝对是黑客攻击。
最初我认为我遇到的问题是框架忽略了我的 android:key,因为 getKey() returns 是一个空字符串,但这不可能是真的,因为它获得了持久性启动 PreferenceScreen 时的值,并在关闭 DialogPreference 时将更改的值保存到共享首选项。
所以看来我正在解决的问题是框架将首选项持久值读入内部成员,然后使用内部成员直到 returns 流出首选项框架,而不刷新它们在 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 是实现此结果的预期方式,但在搜索源代码和 google 寻找答案几天后,我没有找到任何其他东西。
我将把这个答案留给面临同样问题并且有足够勇气尝试我的技巧的其他人。如果(可能是什么时候)我发现黑客有任何问题,我会更新答案。
更好的是,如果其他人可以提供首选解决方案,指出我做错了什么导致了问题,请这样做。
编辑: 工作了这么久之后,那个 hack 最终失败了,而且一直如此。
但是在删除 hack 的同时,我以全新的思路解决了这个问题,并且利用我确定对话框正在获取首选项键这一事实,我使用了这个修复程序来解决这个问题,它工作得很好。
我将这行代码添加到 onBindDialogView 的开头
value = getSharedPreferences().getString(getKey(), "-1");
这使得对 onGetDefaultValue 和 onSetInitialValue 的调用变得多余,但它们并没有按预期工作,至少对我来说是这样。
编辑: 天哪,我讨厌这个!
我没有注意到在较早的重构过程中删除了更新 onDialogClosed 中的 DialogPreference 内部值的代码行。
这通常是一些简单的事情,在我检查的所有其他内容中,我错过了那个小改动。
我只是在 repo 的代码审查中才注意到它,现在我觉得很傻。所以最后不需要额外的代码。