web-dev-qa-db-fra.com

Comment écouter les changements de préférence dans un PreferenceFragment?

Comme décrit ici , je sous-classe PreferenceFragment et l’affiche dans une activité. Ce document explique comment écouter les modifications de préférences ici , mais uniquement si vous sous-classez PreferenceActivity. Comme je ne le fais pas, comment puis-je écouter les changements de préférences?

J'ai essayé d'implémenter OnSharedPreferenceChangeListener dans PreferenceFragment mais cela ne semble pas fonctionner (onSharedPreferenceChanged ne semble jamais être appelé).

C'est mon code jusqu'à présent:

SettingsActivity.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

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 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>

De même, PreferenceFragment est-il même le bon endroit pour écouter les changements de préférences ou dois-je le faire dans le cadre de l'activité?

83

Je crois que vous avez juste besoin d’inscrire/désinscrire la Listener dans votre PreferenceFragment et cela fonctionnera.

@Override
public void onResume() {
    super.onResume();
    getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);

}

@Override
public void onPause() {
    getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    super.onPause();
}

En fonction de ce que vous voulez faire, vous n’avez peut-être pas besoin d’écouter. Les modifications apportées aux préférences sont automatiquement validées avec SharedPreferences.

138
antew

La solution de antew fonctionne bien, vous pouvez voir ici une activité de préférence complète pour 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");

    }
}
}
25

Toutes les autres réponses sont correctes. Mais j'aime mieux cette alternative parce que vous avez immédiatement l'instance de préférence qui a provoqué le changement.

@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;
        }
    });
}
13
Zsolt Safrany

Cela a fonctionné pour moi de PreferenceFragment.onCreate ()

OnSharedPreferenceChangeListener listener = 
    new SharedPreferences.OnSharedPreferenceChangeListener()
    {
        public void onSharedPreferenceChanged(SharedPreferences prefs, String key)
        {
         showDialog();
        }
    };
2
Gene Bo

Un autre exemple complet pour que vous puissiez voir la photo entière.

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);
        }
    }
}
0

J'ai récemment fini d'assembler ma propre PreferenceScreen à l'aide du Preferences API. Je pensais donc donner mon propre exemple complet .. Cela inclut la mise à jour de la Summary en valeur nouvelle/modifiée, ainsi que l'écoute et la réaction aux modifications.

PS. Pour répondre à votre dernière question: Pour afficher une valeur par défaut pour Summary lors de la création initiale de la variable PreferenceScreen (avant toute modification de la valeur), vous pouvez définir simplement le Android:summary à une valeur de votre choix, de l'intérieur le fichier preferences.xml directement - et puis, une fois que il y a un changement dans la valeur, il sera mis à jour automatiquement en utilisant le code contenu dans mon exemple ci-dessous. Personnellement, j'utilise une brève explication de Preference comme étant ma Summary initiale, définie dans mon preferences.xml, puis une fois que la valeur fait est modifiée pour la première fois, elle affichera simplement la valeur actuelle en tant que Summary à partir de là ..

Quoi qu'il en soit, voici ma pleine Exemple:

SettingsFragment.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() {
    super.onPause();

    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
}
}


J'espère que ça aide!
Toute rétroaction positive est grandement appréciée, car je suis relativement nouveau dans StackOverflow;)
Joyeux codage!

0
Studio2bDesigns

Voici un moyen de le faire et d'éviter toute fuite de mémoire potentielle:

@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);
}
0
Eaweb

Vous devez simplement supprimer la classe Prefernce spécifiée dans votre méthode onResume(). Dans mon cas, j'utilisais la classe SwitchPreference, donc le code serait comme- 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);

    }

Ensuite, dans l'activité pour laquelle vous voulez utiliser la valeur PrefernceFragment, utilisez simplement l'objet SharedPreference pour appeler les valeurs et le déclencher.

0
Prajwal W