如何在首选项摘要中显示 Android 首选项的当前值?
Posted
技术标签:
【中文标题】如何在首选项摘要中显示 Android 首选项的当前值?【英文标题】:How do I display the current value of an Android Preference in the Preference summary? 【发布时间】:2010-10-06 14:18:06 【问题描述】:这一定经常出现。
当用户在 android 应用中编辑首选项时,我希望他们能够在 Preference
摘要中看到当前设置的首选项值。
示例:如果我有“丢弃旧邮件”的首选项设置,该设置指定了邮件需要在多少天后被清理。在PreferenceActivity
我希望用户看到:
“丢弃旧消息”
“在 x 天后清理邮件” summary 其中 x 是当前的偏好值
额外的功劳:使它可重复使用,因此我可以轻松地将其应用于我的所有偏好,而不管它们的类型如何(这样它就可以与 EditTextPreference、ListPreference 等一起使用,并且只需最少的编码)。
【问题讨论】:
【参考方案1】:我已经看到所有投票的答案都显示了如何使用确切的当前值设置摘要,但 OP 还想要类似的东西:
“在 x 天后清理邮件”* x 是当前的偏好值
这是我实现这一目标的答案
根据ListPreference.getSummary()
上的documentation:
返回此 ListPreference 的摘要。如果摘要中有一个字符串格式标记(即“%s”或“%1$s”),那么当前 条目值将被替换。
但是,我在几台设备上尝试了此方法,但似乎不起作用。通过一些研究,我在this answer 中找到了一个很好的解决方案。它只是包括扩展您使用的每个 Preference
并覆盖 getSummary()
以按照 Android 文档的规定工作。
【讨论】:
它最初似乎确实有效,但是当您选择一个新值时,它不会自动更新,直到您执行某些操作以使整个活动无效并导致它重绘。我使用的是 Android 4.0.4。 如果 Google 可以将格式化字符串添加到首选项对象,那就太好了。【参考方案2】:在 Android Studio 中,打开“root_preferences.xml”,选择设计模式。选择所需的 EditTextPreference 首选项,然后在“所有属性”下,查找“useSimpleSummaryProvider”属性并将其设置为 true。然后它将显示当前值。
【讨论】:
重复的答案,但我喜欢这个解决方案【参考方案3】:根据Android docs可以在ListPreference和EditTextPreference组件中使用app:useSimpleSummaryProvider="true"
。
【讨论】:
如果您使用androidx.preference.EditTextPreference
,这实际上应该是公认的答案【参考方案4】:
如果您使用的是 AndroidX,您可以use a custom SummaryProvider
。这种方法可以用于任何Preference
。
文档中的示例(Java):
EditTextPreference countingPreference = (EditTextPreference) findPreference("counting");
countingPreference.setSummaryProvider(new SummaryProvider<EditTextPreference>()
@Override
public CharSequence provideSummary(EditTextPreference preference)
String text = preference.getText();
if (TextUtils.isEmpty(text))
return "Not set";
return "Length of saved value: " + text.length();
);
文档示例 (Kotlin):
val countingPreference = findPreference("counting") as EditTextPreference
countingPreference.summaryProvider = SummaryProvider<EditTextPreference> preference ->
val text = preference.text
if (TextUtils.isEmpty(text))
"Not set"
else
"Length of saved value: " + text.length
【讨论】:
【参考方案5】:由于在androidx Preference 类中有SummaryProvider 接口,它可以在没有OnSharedPreferenceChangeListener 的情况下完成。为 EditTextPreference 和 ListPreference 提供了简单的实现。以EddieB's answer 为基础,它可能看起来像这样。在 androidx.preference:preference:1.1.0-alpha03 上测试。
package com.example.util.timereminder.ui.prefs;
import android.os.Bundle;
import com.example.util.timereminder.R;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
/**
* Displays different preferences.
*/
public class PrefsFragmentExample extends PreferenceFragmentCompat
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
addPreferencesFromResource(R.xml.preferences);
initSummary(getPreferenceScreen());
/**
* Walks through all preferences.
*
* @param p The starting preference to search from.
*/
private void initSummary(Preference p)
if (p instanceof PreferenceGroup)
PreferenceGroup pGrp = (PreferenceGroup) p;
for (int i = 0; i < pGrp.getPreferenceCount(); i++)
initSummary(pGrp.getPreference(i));
else
setPreferenceSummary(p);
/**
* Sets up summary providers for the preferences.
*
* @param p The preference to set up summary provider.
*/
private void setPreferenceSummary(Preference p)
// No need to set up preference summaries for checkbox preferences because
// they can be set up in xml using summaryOff and summary On
if (p instanceof ListPreference)
p.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
else if (p instanceof EditTextPreference)
p.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
【讨论】:
【参考方案6】:1行代码的简洁解决方案:
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
bindPreferenceSummaryToValue(findPreference("mySetting"));
// initialize summary
sBindPreferenceSummaryToValueListener.onPreferenceChange(findPreference("mySetting"),
((ListPreference) findPreference("mySetting")).getEntry());
【讨论】:
好的,什么是 bindPreferenceSummaryToValue() ?另外,这不是你说的一行代码。【参考方案7】:我发现这种方法可以从支持库句柄"%s"
中生成EditTextPreference
概括起来(因为ListPreference
已经处理):
public class EditTextPreference extends android.support.v7.preference.EditTextPreference
public EditTextPreference(Context context, AttributeSet attrs)
super(context, attrs);
@Override
public void setText(String text)
super.setText(text);
notifyChanged();
@Override
public CharSequence getSummary()
String text = super.getText();
String summary = super.getSummary().toString();
return String.format(summary, text == null ? "" : text);
在 xml 中它看起来像这样:
<com.example.yourapp.EditTextPreference
android:defaultValue="1"
android:key="cleanup_period"
android:summary="Clean up messages after %s days"
android:title="Clean up period" />
【讨论】:
【参考方案8】:可能像 ListPreference:修改 getSummary 得到你想要的:
package your.package.preference;
import android.content.Context;
import android.util.AttributeSet;
public class EditTextPreference extends android.preference.EditTextPreference
public EditTextPreference(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
public EditTextPreference(Context context, AttributeSet attrs)
super(context, attrs);
public EditTextPreference(Context context)
super(context);
@Override
public CharSequence getSummary()
if(super.getSummary() == null) return null;
String summary = super.getSummary().toString();
return String.format(summary, getText());
并在您的 xml 中使用它:
<your.package.EditTextPreference
android:key="pref_alpha"
android:summary="Actual value: %s"
android:title="Title"
android:defaultValue="default"
/>
因此您可以使用%s
而不是实际值来编写摘要。
【讨论】:
@Eruvanos @serv-inc 至少使用android.support.v7.preference.EditTextPreference
的子类,这不会在首选项更改时更新摘要,仅在创建首选项活动时。在首选项片段类中不实现OnSharedPreferenceChangeListener.onSharedPreferenceChanged
的一种解决方法是也覆盖android.support.v7.preference.EditTextPreference.setText(String text)
:@Override public void setText(String text) super.setText(text); this.setSummary(this.getText());
@PointedEars:完成。但这似乎也是***.com/a/21906829/1587329的副本【参考方案9】:
因为我使用的是自定义 PreferenceDataStore
,所以我无法为某些 SharedPreference
添加监听器,所以我不得不编写一个有点老套的解决方案来监听每个偏好:
class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener
private val handler: Handler by lazy Handler(Looper.getMainLooper())
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?)
preferenceManager.preferenceDataStore = prefs
addPreferencesFromResource(R.xml.app_preferences)
onPreferenceChange(preferenceScreen, null)
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean
preference.onPreferenceChangeListener = this
when (preference)
is PreferenceGroup -> for (i in 0 until preference.preferenceCount)
onPreferenceChange(preference.getPreference(i), null)
is ListPreference ->
if (preference.value == null)
preference.isPersistent = false
preference.value = Preference::class.java.getDeclaredField("mDefaultValue")
.apply isAccessible = true
.get(preference).toString()
preference.isPersistent = true
postPreferenceUpdate(Runnable preference.summary = preference.entry )
return true
/**
* We can't directly update the preference summary update because [onPreferenceChange]'s result
* is used to decide whether or not to update the pref value.
*/
private fun postPreferenceUpdate(r: Runnable) = handler.post(r)
【讨论】:
【参考方案10】:这是基于@tdeveaux 答案的PreferenceFragment
内的所有EditTextPreference
s 的有效解决方案:
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener
private static final String TAG = "SettingsFragment";
@Override
public void onCreate (Bundle savedInstanceState)
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
@Override
public void onResume ()
super.onResume();
for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); ++i)
Preference preference = getPreferenceScreen().getPreference(i);
updatePreference(preference);
@Override
public void onSharedPreferenceChanged (SharedPreferences sharedPreferences, String key)
updatePreference(findPreference(key));
private void updatePreference (Preference preference)
if (preference instanceof EditTextPreference)
EditTextPreference editTextPreference = (EditTextPreference)preference;
editTextPreference.setSummary(editTextPreference.getText());
【讨论】:
你必须注销监听器【参考方案11】:这是您将摘要设置为所选值所需的代码。它还在启动时设置值并尊重默认值,而不仅仅是在更改时。只需将“R.layout.prefs”更改为您的 xml 文件并根据您的需要扩展 setSummary 方法。它实际上只处理 ListPreferences,但很容易自定义以尊重其他 Preferences。
package de.koem.timetunnel;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
public class Prefs
extends PreferenceActivity
implements OnSharedPreferenceChangeListener
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
this.addPreferencesFromResource(R.layout.prefs);
this.initSummaries(this.getPreferenceScreen());
this.getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
/**
* Set the summaries of all preferences
*/
private void initSummaries(PreferenceGroup pg)
for (int i = 0; i < pg.getPreferenceCount(); ++i)
Preference p = pg.getPreference(i);
if (p instanceof PreferenceGroup)
this.initSummaries((PreferenceGroup) p); // recursion
else
this.setSummary(p);
/**
* Set the summaries of the given preference
*/
private void setSummary(Preference pref)
// react on type or key
if (pref instanceof ListPreference)
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
/**
* used to change the summary of a preference
*/
public void onSharedPreferenceChanged(SharedPreferences sp, String key)
Preference pref = findPreference(key);
this.setSummary(pref);
// private static final String LOGTAG = "Prefs";
koem
【讨论】:
非常感谢!我由此创建了一个类,将资源 id 作为参数提供给 onCreate() —— 这样,我的设置屏幕只需一行更改即可让它们以摘要形式显示值。 顺便说一句:请注意,使用此系统不会更新非持久性首选项。必须使用个人首选项的setOnPreferenceChangeListener(Preference.OnPreferenceChangeListener onPreferenceChangeListener)
-方法来监听对它们的更改。【参考方案12】:
我的解决方案是创建一个自定义EditTextPreference
,在 XML 中使用如下:<com.example.EditTextPreference android:title="Example Title" />
EditTextPreference.java:-
package com.example;
import android.content.Context;
import android.util.AttributeSet;
public class EditTextPreference extends android.preference.EditTextPreference
public EditTextPreference(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
public EditTextPreference(Context context, AttributeSet attrs)
super(context, attrs);
public EditTextPreference(Context context)
super(context, null);
@Override
protected void onDialogClosed(boolean positiveResult)
super.onDialogClosed(positiveResult);
setSummary(getSummary());
@Override
public CharSequence getSummary()
return getText();
【讨论】:
【参考方案13】:Android documentation 表示可以在getSummary()
中使用字符串格式标记:
如果摘要中有一个字符串格式标记(即“%s”或“%1$s”),则当前条目值将被替换。
只需在 ListPreference xml 声明中指定 android:summary="Clean up messages after %s days"
对我有用。
注意:这仅适用于ListPreference
。
【讨论】:
如果我错了,请有人纠正我,但 getSummary() 的文档指出它是在 API 级别 1 中添加的。您是否暗示首次发布时行为有所不同? 不幸的是,这仅适用于 ListPreference。我希望 EditTextPreference 具有相同的行为。令人惊讶的是,Google 并未为所有 DialogPreferences 添加此功能。 另外,只要没有设置值,我就不会工作 - 在第一次调用 Preference 活动时,它只显示 %s,这真的很愚蠢。 @Zordid 这可以通过在您的 xml 中指定默认值来修复,例如您的 ListPreference 中的android:defaultValue="0"
。这是最明智的答案,对我有用。
@Mohit Singh / @Zordid,在 Lollipop API 22 上,defaultValue
和 %s
不起作用。在其他版本上,通常它可以工作。请问有什么解决办法吗?我当然不想为此编写自定义类。令人难以置信的是,Google 让最琐碎的任务变得如此痛苦。【参考方案14】:
这是我的解决方案... FWIW
package com.example.PrefTest;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
public class Preferences extends PreferenceActivity implements
OnSharedPreferenceChangeListener
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
PreferenceManager.setDefaultValues(Preferences.this, R.xml.preferences,
false);
initSummary(getPreferenceScreen());
@Override
protected void onResume()
super.onResume();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
@Override
protected void onPause()
super.onPause();
// Unregister the listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key)
updatePrefSummary(findPreference(key));
private void initSummary(Preference p)
if (p instanceof PreferenceGroup)
PreferenceGroup pGrp = (PreferenceGroup) p;
for (int i = 0; i < pGrp.getPreferenceCount(); i++)
initSummary(pGrp.getPreference(i));
else
updatePrefSummary(p);
private void updatePrefSummary(Preference p)
if (p instanceof ListPreference)
ListPreference listPref = (ListPreference) p;
p.setSummary(listPref.getEntry());
if (p instanceof EditTextPreference)
EditTextPreference editTextPref = (EditTextPreference) p;
if (p.getTitle().toString().toLowerCase().contains("password"))
p.setSummary("******");
else
p.setSummary(editTextPref.getText());
if (p instanceof MultiSelectListPreference)
EditTextPreference editTextPref = (EditTextPreference) p;
p.setSummary(editTextPref.getText());
【讨论】:
这确实很好用@EddieB...除了我在偏好屏幕中有一个偏好屏幕。知道如何到达内部偏好屏幕并使用摘要填充这些屏幕吗? @taraloca - 改变 if (p instanceof PreferenceCategory) PreferenceCategory pCat = (PreferenceCategory) p; to if (p instanceof PreferenceGroup) final PreferenceGroup pCat = (PreferenceGroup) p; 这很好用,如果EditTextPreference
是 android:password="true"
它会显示值
如果没有定义值(即if editTextPref.getText() == ""
),我应该如何修改代码以显示资源(xml)文件中的摘要?如何在updatePrefSummary
获得汇总值? p.getSummary()
和 editTextPref.getSummary()
返回已修改的值。
因为PreferenceCategory
和PreferenceScreen
都继承自PreferenceGroup
,所以我将initSummary
改为处理PreferenceGroup
。这避免了在onCreate()
中需要另一个循环。行为变化:嵌套的 PreferenceScreens 现在也可以递归处理。【参考方案15】:
对于EditTextPreference:
当然,如果您需要特定的 edittextpreference 但您可以对每个 Preference 执行此操作,我当然会想到这个解决方案:
............
private static final String KEY_EDIT_TEXT_PREFERENCE2 = "on_a1";
public static String value = "";
............
private void updatePreference(Preference preference, String key)
if (key.equals(KEY_EDIT_TEXT_PREFERENCE2))
preference = findPreference(key);
if (preference instanceof EditTextPreference)
editTextPreference = (EditTextPreference) preference;
editTextPreference.setSummary(editTextPreference.getText());
value = editTextPreference.getText().toString();
return;
SharedPreferences sharedPrefs = getPreferenceManager().getSharedPreferences();
preference.setSummary(sharedPrefs.getString(KEY_EDIT_TEXT_PREFERENCE2, ""));
然后在 onResume();
@Override
public void onResume()
super.onResume();
SharedPreferences etext = getPreferenceManager().getSharedPreferences();
String str = etext.getString("value", "");
editTextPreference = (EditTextPreference) findPreference(KEY_EDIT_TEXT_PREFERENCE2);
editTextPreference.setText(str);
editTextPreference.setSummary(editTextPreference.getText());
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
在:
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
updatePreference(findPreference(key), key);
【讨论】:
【参考方案16】:如果你使用PreferenceFragment
,我就是这样解决的。这是不言自明的。
public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
@Override
public void onResume()
super.onResume();
for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); ++i)
Preference preference = getPreferenceScreen().getPreference(i);
if (preference instanceof PreferenceGroup)
PreferenceGroup preferenceGroup = (PreferenceGroup) preference;
for (int j = 0; j < preferenceGroup.getPreferenceCount(); ++j)
Preference singlePref = preferenceGroup.getPreference(j);
updatePreference(singlePref, singlePref.getKey());
else
updatePreference(preference, preference.getKey());
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
updatePreference(findPreference(key), key);
private void updatePreference(Preference preference, String key)
if (preference == null) return;
if (preference instanceof ListPreference)
ListPreference listPreference = (ListPreference) preference;
listPreference.setSummary(listPreference.getEntry());
return;
SharedPreferences sharedPrefs = getPreferenceManager().getSharedPreferences();
preference.setSummary(sharedPrefs.getString(key, "Default"));
【讨论】:
这个解决方案需要更多的选票...开发者网站上的示例显示这让我很烦恼,但完全省略了它。 若要获取 EditTextPreferences 也已更新,请将其添加到updatePreference
CODE if (preference instanceof EditTextPreference) EditTextPreference editTextPref = (EditTextPreference) preference; preference.setSummary(editTextPref.getText());
感谢@EddieB
你在哪里打电话unregisterOnSharedPreferenceChangeListener
?
findPreference(CharSequence key) This method was deprecated in API level 11. This function is not relevant for a modern fragment-based PreferenceActivity.
@DSlomer64 我很清楚你在引用什么。它告诉你不要使用PreferenceActivity.findPreference
(和其他几种方法),因为谷歌希望你切换到这个答案中显示的技术,它使用PreferenceFragment.findPreference
。【参考方案17】:
您必须在 onCreate 方法上使用 bindPreferenceSummaryToValue 函数。
例子:
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
// Add 'general' preferences, defined in the XML file
addPreferencesFromResource(R.xml.pref_general);
// For all preferences, attach an OnPreferenceChangeListener so the UI summary can be
// updated when the preference changes.
bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_location_key)));
bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_units_key)));
请参阅 Udacity Android 课程的第 3 课:https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601
【讨论】:
【参考方案18】:仅供参考:
findPreference(CharSequence key)
This method was deprecated in API level 11. This function is not relevant
for a modern fragment-based PreferenceActivity.
更有理由看一下上面@ASD (source found here) 中非常漂亮的Answer
,它说在android:summary
中为preferences.xml
中的每个字段使用%s
。 (当前偏好值替换为%s
。)
<ListPreference
...
android:summary="Length of longest word to return as match is %s"
...
/>
【讨论】:
【参考方案19】:简单地说:
listPreference.setSummary("%s");
【讨论】:
【参考方案20】:如果有人仍在寻找此问题的答案,您应该查看thirtythreefortys 的答案。
<ListPreference
android:key="pref_list"
android:title="A list of preferences"
android:summary="%s"
android:entries="@array/pref_list_entries"
android:entryValues="@array/pref_list_entries_values"
android:defaultValue="0" />
Android 会将 %s 替换为首选项的当前字符串值,如 ListPreference 的选择器所示。
【讨论】:
有效。这是当今最简单、最好的解决方案。 请注意,“%s”可以放在摘要字符串中的任何位置。是的,这包括资源字符串!【参考方案21】:对于 EditTextPreference:
public class MyEditTextPreference extends EditTextPreference
public MyEditTextPreference(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
public MyEditTextPreference(Context context, AttributeSet attrs)
super(context, attrs);
@Override
public void setText(String text)
super.setText(text);
setSummary(text);
【讨论】:
【参考方案22】:您可以覆盖默认的 Preference 类并实现该功能。
public class MyListPreference extends ListPreference
public MyListPreference(Context context) super(context);
public MyListPreference(Context context, AttributeSet attrs) super(context, attrs);
@Override
public void setValue(String value)
super.setValue(value);
setSummary(getEntry());
稍后在您的 xml 中,您可以使用自定义首选项,例如
<your.package.name.MyListPreference
android:key="noteInterval"
android:defaultValue="60"
android:title="Notification Interval"
android:entries="@array/noteInterval"
android:entryValues="@array/noteIntervalValues"
/>
【讨论】:
优秀的简单方法。请注意 getEntry 字符串中的 % 之类的内容,因为它们可能会导致问题(或者它们对我造成了问题)【参考方案23】:感谢 Reto 的详细解释!
如果这对任何人有任何帮助,我必须更改 Reto Meier 提出的代码以使其与适用于 Android 1.5 的 SDK 一起使用
@Override
protected void onResume()
super.onResume();
// Setup the initial values
mListPreference.setSummary("Current value is " + mListPreference.getEntry().toString());
// Set up a listener whenever a key changes
...
同样的变化也适用于回调函数onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
干杯,
克里斯
【讨论】:
【参考方案24】:这里,所有这些都是从 Eclipse 示例SettingsActivity
中截取的。
我必须复制所有这些太多的代码来展示这些 android 开发人员如何完美地选择更通用和更稳定的编码风格。
我留下了使PreferenceActivity
适应平板电脑和更高 API 的代码。
public class SettingsActivity extends PreferenceActivity
@Override
protected void onPostCreate(Bundle savedInstanceState)
super.onPostCreate(savedInstanceState);
setupSummaryUpdatablePreferencesScreen();
private void setupSummaryUpdatablePreferencesScreen()
// In the simplified UI, fragments are not used at all and we instead
// use the older PreferenceActivity APIs.
// Add 'general' preferences.
addPreferencesFromResource(R.xml.pref_general);
// Bind the summaries of EditText/List/Dialog preferences to
// their values. When their values change, their summaries are updated
// to reflect the new value, per the Android Design guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener()
private String TAG = SettingsActivity.class.getSimpleName();
@Override
public boolean onPreferenceChange(Preference preference, Object value)
String stringValue = value.toString();
if (preference instanceof ListPreference)
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
else
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
Log.i(TAG, "pref changed : " + preference.getKey() + " " + value);
return true;
;
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* @see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference)
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
xml/pref_general.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- NOTE: EditTextPreference accepts EditText attributes. -->
<!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
<EditTextPreference
android:capitalize="words"
android:defaultValue="@string/pref_default_display_name"
android:inputType="textCapWords"
android:key="example_text"
android:maxLines="1"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/pref_title_display_name" />
<!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog todismiss it.-->
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
<ListPreference
android:defaultValue="-1"
android:entries="@array/pref_example_list_titles"
android:entryValues="@array/pref_example_list_values"
android:key="example_list"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:title="@string/pref_title_add_friends_to_messages" />
</PreferenceScreen>
values/strings_activity_settings.xml
<resources>
<!-- Strings related to Settings -->
<!-- Example General settings -->
<string name="pref_title_display_name">Display name</string>
<string name="pref_default_display_name">John Smith</string>
<string name="pref_title_add_friends_to_messages">Add friends to messages</string>
<string-array name="pref_example_list_titles">
<item>Always</item>
<item>When possible</item>
<item>Never</item>
</string-array>
<string-array name="pref_example_list_values">
<item>1</item>
<item>0</item>
<item>-1</item>
</string-array>
</resources>
注意:实际上我只想评论“Google 的 PreferenceActivity 示例也很有趣”。但是我的声望点不够。所以请不要怪我。
(抱歉英语不好)
【讨论】:
【参考方案25】:这是我的解决方案:
构建首选项类型“getter”方法。
protected String getPreference(Preference x)
// http://***.com/questions/3993982/how-to-check-type-of-variable-in-java
if (x instanceof CheckBoxPreference)
return "CheckBoxPreference";
else if (x instanceof EditTextPreference)
return "EditTextPreference";
else if (x instanceof ListPreference)
return "ListPreference";
else if (x instanceof MultiSelectListPreference)
return "MultiSelectListPreference";
else if (x instanceof RingtonePreference)
return "RingtonePreference";
else if (x instanceof SwitchPreference)
return "SwitchPreference";
else if (x instanceof TwoStatePreference)
return "TwoStatePreference";
else if (x instanceof DialogPreference) // Needs to be after ListPreference
return "DialogPreference";
else
return "undefined";
构建一个“setSummaryInit”方法。
public void onSharedPreferenceChanged(SharedPreferences prefs, String key)
Log.i(TAG, "+ onSharedPreferenceChanged(prefs:" + prefs + ", key:" + key + ")");
if( key != null )
updatePreference(prefs, key);
setSummary(key);
else
Log.e(TAG, "Preference without key!");
Log.i(TAG, "- onSharedPreferenceChanged()");
protected boolean setSummary()
return _setSummary(null);
protected boolean setSummary(String sKey)
return _setSummary(sKey);
private boolean _setSummary(String sKey)
if (sKey == null) Log.i(TAG, "Initializing");
else Log.i(TAG, sKey);
// Get Preferences
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(this);
// Iterate through all Shared Preferences
// http://***.com/questions/9310479/how-to-iterate-through-all-keys-of-shared-preferences
Map<String, ?> keys = sharedPrefs.getAll();
for (Map.Entry<String, ?> entry : keys.entrySet())
String key = entry.getKey();
// Do work only if initializing (null) or updating specific preference key
if ( (sKey == null) || (sKey.equals(key)) )
String value = entry.getValue().toString();
Preference pref = findPreference(key);
String preference = getPreference(pref);
Log.d("map values", key + " | " + value + " | " + preference);
pref.setSummary(key + " | " + value + " | " + preference);
if (sKey != null) return true;
return false;
private void updatePreference(SharedPreferences prefs, String key)
Log.i(TAG, "+ updatePreference(prefs:" + prefs + ", key:" + key + ")");
Preference pref = findPreference(key);
String preferenceType = getPreference(pref);
Log.i(TAG, "preferenceType = " + preferenceType);
Log.i(TAG, "- updatePreference()");
初始化
创建 PreferenceActivity 并实现 OnSharedPreferenceChangeListener 的公共类
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
PreferenceManager.setDefaultValues(this, R.xml.global_preferences,
false);
this.addPreferencesFromResource(R.xml.global_preferences);
this.getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
protected void onResume()
super.onResume();
setSummary();
【讨论】:
【参考方案26】:我的选择是扩展 ListPreference 并且它很干净:
public class ListPreferenceShowSummary extends ListPreference
private final static String TAG = ListPreferenceShowSummary.class.getName();
public ListPreferenceShowSummary(Context context, AttributeSet attrs)
super(context, attrs);
init();
public ListPreferenceShowSummary(Context context)
super(context);
init();
private void init()
setOnPreferenceChangeListener(new OnPreferenceChangeListener()
@Override
public boolean onPreferenceChange(Preference arg0, Object arg1)
arg0.setSummary(getEntry());
return true;
);
@Override
public CharSequence getSummary()
return super.getEntry();
然后你添加你的settings.xml:
<yourpackage.ListPreferenceShowSummary
android:key="key" android:title="title"
android:entries="@array/entries" android:entryValues="@array/values"
android:defaultValue="first value"/>
【讨论】:
我基于此做了一个解决方案。在我的解决方案中,我有一种方法来设置 entrySummaries 数组,而不是在菜单和摘要中使用条目字符串。这里有一个问题:getEntry() 返回前一个值而不是新值。 实际上 init() 甚至是必要的吗?我刚刚覆盖了 getSummary(),它似乎工作得很好! 似乎比投票最高的解决方案更简单、更清洁!init()
函数对于在用户更改偏好时更新 summary
是必需的。没有它,它只会保留最初的条目。【参考方案27】:
花了几个小时解决这个问题后,我实现了这段代码:
[更新:最终版本列表]
public class MyPreferencesActivity extends PreferenceActivity
...
ListPreference m_updateList;
...
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
m_updateList = (ListPreference) findPreference(getString(R.string.pref_update_interval_key));
String currentValue = m_updateList.getValue();
if (currentValue == null)
m_updateList.setValue((String)m_updateList.getEntryValues()[DEFAULT_UPDATE_TIME_INDEX]);
currentValue = m_updateList.getValue();
updateListSummary(currentValue);
m_updateList.setOnPreferenceChangeListener(new OnPreferenceChangeListener()
@Override
public boolean onPreferenceChange(Preference preference, Object newValue)
updateListSummary(newValue.toString());
return true;
);
private void updateListSummary(String newValue)
int index = m_updateList.findIndexOfValue(newValue);
CharSequence entry = m_updateList.getEntries()[index];
m_updateList.setSummary(entry);
这是唯一对我有用的解决方案。在我尝试从 ListPreferences 子类化并实现 android:summary="bla bla bla %s" 之前。都没有用。
【讨论】:
您的方式比其他方式更清晰,使用的代码更少。最佳答案使用“代理” - 首选项管理器。它不像监听列表中的直接变化那么清楚。 @Subtle Fox,整洁的解决方案。只是好奇您是否执行了“setDefaultValue()”,那么为什么要检查 (ss==null) 因为 setDefaultValue() 不应该存在 :) 我已经在重构之前放置了这段代码【参考方案28】:public class ProfileManagement extends PreferenceActivity implements
OnPreferenceChangeListener
EditTextPreference screenName;
ListPreference sex;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.profile_management);
screenName = (EditTextPreference) findPreference("editTextPref");
sex = (ListPreference) findPreference("sexSelector");
screenName.setOnPreferenceChangeListener(this);
sex.setOnPreferenceChangeListener(this);
@Override
public boolean onPreferenceChange(Preference preference, Object newValue)
preference.setSummary(newValue.toString());
return true;
【讨论】:
【参考方案29】:如果你只想将每个字段的纯文本值显示为它的摘要,那么下面的代码应该是最容易维护的。它只需要进行两次更改(第 13 和 21 行,标有“此处更改”):
package com.my.package;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
public class PreferencesActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener
private final String[] mAutoSummaryFields = "pref_key1", "pref_key2", "pref_key3" ; // change here
private final int mEntryCount = mAutoSummaryFields.length;
private Preference[] mPreferenceEntries;
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences_file); // change here
mPreferenceEntries = new Preference[mEntryCount];
for (int i = 0; i < mEntryCount; i++)
mPreferenceEntries[i] = getPreferenceScreen().findPreference(mAutoSummaryFields[i]);
@SuppressWarnings("deprecation")
@Override
protected void onResume()
super.onResume();
for (int i = 0; i < mEntryCount; i++)
updateSummary(mAutoSummaryFields[i]); // initialization
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); // register change listener
@SuppressWarnings("deprecation")
@Override
protected void onPause()
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); // unregister change listener
private void updateSummary(String key)
for (int i = 0; i < mEntryCount; i++)
if (key.equals(mAutoSummaryFields[i]))
if (mPreferenceEntries[i] instanceof EditTextPreference)
final EditTextPreference currentPreference = (EditTextPreference) mPreferenceEntries[i];
mPreferenceEntries[i].setSummary(currentPreference.getText());
else if (mPreferenceEntries[i] instanceof ListPreference)
final ListPreference currentPreference = (ListPreference) mPreferenceEntries[i];
mPreferenceEntries[i].setSummary(currentPreference.getEntry());
break;
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
updateSummary(key);
【讨论】:
【参考方案30】:我用 ListPreference 的以下后代解决了这个问题:
public class EnumPreference extends ListPreference
public EnumPreference(Context aContext, AttributeSet attrs)
super(aContext,attrs);
@Override
protected View onCreateView(ViewGroup parent)
setSummary(getEntry());
return super.onCreateView(parent);
@Override
protected boolean persistString(String aNewValue)
if (super.persistString(aNewValue))
setSummary(getEntry());
notifyChanged();
return true;
else
return false;
在 1.6 到 4.0.4 中对我来说似乎工作正常。
【讨论】:
以上是关于如何在首选项摘要中显示 Android 首选项的当前值?的主要内容,如果未能解决你的问题,请参考以下文章