[英]How to listen for preference changes within a PreferenceFragment?
As described here , I am subclassing PreferenceFragment and displaying it inside an Activity.如上所述这里,我继承PreferenceFragment并显示它的活动中。 That document explains how to listen for preference changes here , but only if you subclass PreferenceActivity.
该文档解释了如何在此处侦听首选项更改,但前提是您将 PreferenceActivity 子类化。 Since I'm not doing that, how do I listen for preference changes?
既然我没有这样做,我该如何听取偏好的变化?
I've tried implementing OnSharedPreferenceChangeListener in my PreferenceFragment but it does not seem to work ( onSharedPreferenceChanged
never seems to get called).我已经尝试在我的 PreferenceFragment 中实现 OnSharedPreferenceChangeListener 但它似乎不起作用(
onSharedPreferenceChanged
似乎从未被调用)。
This is my code so far:到目前为止,这是我的代码:
SettingsActivity.java设置Activity.java
public class SettingsActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}
}
SettingsFragment.java设置片段.java
public class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener
{
public static final String KEY_PREF_EXERCISES = "pref_number_of_exercises";
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
//IT NEVER GETS IN HERE!
if (key.equals(KEY_PREF_EXERCISES))
{
// Set summary to be the user-description for the selected value
Preference exercisesPref = findPreference(key);
exercisesPref.setSummary(sharedPreferences.getString(key, ""));
}
}
}
preferences.xml首选项.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:defaultValue="15"
android:enabled="true"
android:key="pref_number_of_exercises"
android:numeric="integer"
android:title="Number of exercises" />
</PreferenceScreen>
Also, is the PreferenceFragment even the right place to listen for preference changes or should I do it within the Activity?此外,PreferenceFragment 甚至是监听偏好更改的正确位置还是我应该在 Activity 中执行此操作?
I believe you just need to register/unregister the Listener
in your PreferenceFragment
and it will work.我相信你只需要在你的
PreferenceFragment
注册/取消注册Listener
,它就会工作。
@Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
Depending on what you want to do you may not need to use a listener.根据您想要做什么,您可能不需要使用侦听器。 Changes to the preferences are committed to
SharedPreferences
automatically.对首选项的更改会自动提交给
SharedPreferences
。
The solution of antew works well, here you can see a full preference activity for Android v11 onwards: antew 的解决方案效果很好,在这里您可以看到 Android v11 以后的完整偏好活动:
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceFragment;
public class UserPreferencesV11 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction().replace(android.R.id.content,
new PrefsFragment()).commit();
}
public static class PrefsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
// set texts correctly
onSharedPreferenceChanged(null, "");
}
@Override
public void onResume() {
super.onResume();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
super.onPause();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// just update all
ListPreference lp = (ListPreference) findPreference(PREF_YOUR_KEY);
lp.setSummary("dummy"); // required or will not update
lp.setSummary(getString(R.string.pref_yourKey) + ": %s");
}
}
}
All the other answers are correct.所有其他答案都是正确的。 But I like this alternative better because you immediately have the Preference instance that caused the change.
但我更喜欢这个替代方案,因为您立即拥有导致更改的 Preference 实例。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Preference pref = findPreference(getString(R.string.key_of_pref));
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// do whatever you want with new value
// true to update the state of the Preference with the new value
// in case you want to disallow the change return false
return true;
}
});
}
This worked for me from PreferenceFragment.onCreate()这从 PreferenceFragment.onCreate() 对我有用
OnSharedPreferenceChangeListener listener =
new SharedPreferences.OnSharedPreferenceChangeListener()
{
public void onSharedPreferenceChanged(SharedPreferences prefs, String key)
{
showDialog();
}
};
Here is one way to do it and avoid any potential memory leaks:这是一种避免任何潜在内存泄漏的方法:
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.pref_movies);
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
//starts live change listener
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onDestroyView () {
super.onDestroyView();
//Unregisters listener here
PreferenceManager.getDefaultSharedPreferences(getContext())
.unregisterOnSharedPreferenceChangeListener(this);
}
Another complete example so you see the entire picture.另一个完整的例子,让你看到整个画面。
public class SettingsActivity extends AppCompatPreferenceActivity {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener
sBindPreferenceSummaryToValueListener =
new Preference.OnPreferenceChangeListener() {
@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 if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null);
} else {
// Set the summary to reflect the new ringtone display
// name.
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
/**
* 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(), ""));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
}
/**
* Set up the {@link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
if (!super.onMenuItemSelected(featureId, item)) {
NavUtils.navigateUpFromSameTask(this);
}
return true;
}
return super.onMenuItemSelected(featureId, item);
}
/**
* {@inheritDoc}
*/
@Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
/**
* {@inheritDoc}
*/
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName)
|| GPSLocationPreferenceFragment.class.getName().equals(fragmentName)
|| DataSyncPreferenceFragment.class.getName().equals(fragmentName)
|| NotificationPreferenceFragment.class.getName().equals(fragmentName);
}
////////////////// NEW PREFERENCES ////////////////////////////
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GPSLocationPreferenceFragment extends PreferenceFragment {
Preference prefGPSServerAddr, prefGPSASDID, prefIsGPSSwitch;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_gps_location);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("gpsServer_Addr"));
bindPreferenceSummaryToValue(findPreference("gpsASD_ID"));
prefGPSServerAddr = findPreference("gpsServer_Addr");
prefGPSServerAddr.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
try {
// do whatever you want with new value
}
catch (Exception ex)
{
Log.e("Preferences", ex.getMessage());
}
// true to update the state of the Preference with the new value
// in case you want to disallow the change return false
return true;
}
});
prefGPSASDID = findPreference("gpsASD_ID");
prefGPSASDID.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
try {
// do whatever you want with new value
}
catch (Exception ex)
{
Log.e("Preferences", ex.getMessage());
}
// true to update the state of the Preference with the new value
// in case you want to disallow the change return false
return true;
}
});
prefIsGPSSwitch = findPreference("isGPS_Switch");
prefIsGPSSwitch.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
try {
// do whatever you want with new value
}
catch (Exception ex)
{
Log.e("Preferences", ex.getMessage());
}
// true to update the state of the Preference with the new value
// in case you want to disallow the change return false
return true;
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
boolean tabletSize = getResources().getBoolean(R.bool.isTablet);
if (tabletSize) {
startActivity(new Intent(getActivity(), MainActivity.class));
} else {
startActivity(new Intent(getActivity(), SettingsActivity.class));
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
///////////////////////////////////////////////////////////////
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_notification);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
boolean tabletSize = getResources().getBoolean(R.bool.isTablet);
if (tabletSize) {
startActivity(new Intent(getActivity(), MainActivity.class));
} else {
startActivity(new Intent(getActivity(), SettingsActivity.class));
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows data and sync preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class DataSyncPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_data_sync);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("sync_frequency"));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
boolean tabletSize = getResources().getBoolean(R.bool.isTablet);
if (tabletSize) {
startActivity(new Intent(getActivity(), MainActivity.class));
} else {
startActivity(new Intent(getActivity(), SettingsActivity.class));
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
I recently finished putting together my own PreferenceScreen
using the Preferences API
, so I thought I would contribute my own full Example.. This includes updating the Summary
to new/changed Value, as well as Listening for and reacting to changes.我最近完成组建自己
PreferenceScreen
使用Preferences API
,所以我想我会贡献我自己的完整的例子。这包括更新Summary
,以新的/改变的价值,以及听力和反应的变化。
PS.附注。 To answer your last question: To show a default Value for
Summary
upon initial creation of the PreferenceScreen
(prior to any change in the Value), you could simply set the android:summary
to a Value of your choosing, from within the preferences.xml
file directly - and then, once there is a change in the Value, it will update automatically by using the code contained in my Example below.要回答你的最后一个问题:要显示的默认值
Summary
在初始创建的PreferenceScreen
(之前的值的任何变化),你可以简单地设置android:summary
您选择的值,从内部preferences.xml
直接文件 - 然后,一旦值发生更改,它将使用下面示例中包含的代码自动更新。 Personally , I use a short explanation of the Preference
as my initial Summary
, set within my preferences.xml
, and then once the Value does get changed for the first time, it will simply show the current Value as the Summary
from then on..就个人而言,我使用的简短说明
Preference
作为我的初步Summary
,我中设置preferences.xml
,然后一旦该值没有得到改变,第一次,它只会显示当前值作为Summary
从此..
Anyhow , here is my full Example:无论如何,这是我的完整示例:
SettingsFragment.java设置片段.java
public class SettingsFragment extends PreferenceFragment {
public static final String PREF_NOTIFICATION_MODE = "pref_notificationMode";
private SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;
@Override
public void onCreate (@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
final SharedPreferences getPrefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
preferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(PREF_NOTIFICATION_MODE)) {
Preference notifModePref = findPreference(key);
notifModePref.setSummary(sharedPreferences.getString(key, ""));
// DO SOMETHING ELSE HERE WHEN (PREF_NOTIFICATION_MODE) IS CHANGED
}
}
};
}
@Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(preferenceChangeListener);
Preference notifModePref = findPreference(PREF_NOTIFICATION_MODE);
notifModePref.setSummary(getPreferenceScreen().getSharedPreferences().getString(PREF_NOTIFICATION_MODE, ""));
}
@Override
public void onPause() {
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
super.onPause();
}
}
I hope this helps!我希望这有帮助!
Any positive feedback is greatly appreciated, as I'm fairly new to StackOverflow ;)非常感谢任何积极的反馈,因为我对 StackOverflow 还很陌生;)
Happy coding!快乐编码!
You just need to delare the specified Prefernce class in your onResume()
method.您只需要在
onResume()
方法中取消指定的 Prefernce 类。 In my case I was using SwitchPreference
class, therefore the code would be like- SettingsActivity.class在我的情况下,我使用的是
SwitchPreference
类,因此代码类似于- SettingsActivity.class
public static class PrivacyPreferenceFragment extends PreferenceFragment
{
public SwitchPreference switchPreference;
@Override
public void onResume() {
super.onResume();
switchPreference = (SwitchPreference) findPreference("privacy_notice_check");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_privacy);
setHasOptionsMenu(true);
}
Then in the activity where you want to use the PrefernceFragment
value, just use the SharedPreference
object to call the values and trigger it.然后在要使用
PrefernceFragment
值的活动中,只需使用SharedPreference
对象来调用值并触发它。
If you only want to update the summary, using androidx preference library (see the official guides ), and adding the following attribute in your layout xml will be enough:如果您只想更新摘要,使用androidx 首选项库(请参阅官方指南),并在您的布局 xml 中添加以下属性就足够了:
<EditTextPreference
...
app:useSimpleSummaryProvider="true" />
Solution on Kotlin with PreferenceFragmentCompat使用 PreferenceFragmentCompat 在 Kotlin 上的解决方案
https://developer.android.com/reference/androidx/preference/PreferenceFragmentCompat https://developer.android.com/reference/androidx/preference/PreferenceFragmentCompat
Listen when prefChange当 prefChange 时收听
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
val prefListener =
OnSharedPreferenceChangeListener { prefs, key ->
val valueChanged = preferenceManager.sharedPreferences.getString(key,key)
when(valueChanged){
getString(R.string.value_lang_en) -> applyLang(valueChanged)
getString(R.string.value_lang_th) -> applyLang(valueChanged)
}
}
preferenceManager.
sharedPreferences.
registerOnSharedPreferenceChangeListener(prefListener)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.