PreferenceFragment içindeki tercih değişiklikleri nasıl dinlenir?


93

Açıklandığı gibi burada , ben PreferenceFragment sınıflara ve bir Faaliyet içine görüntülendiği duyuyorum. Bu belge, burada tercih değişikliklerini nasıl dinleyeceğinizi açıklar , ancak yalnızca PreferenceActivity'yi alt sınıflarsanız. Bunu yapmadığıma göre, tercih değişikliklerini nasıl dinlerim?

PreferenceFragment'ımda OnSharedPreferenceChangeListener'ı uygulamayı denedim ama işe yaramıyor gibi görünüyor ( onSharedPreferenceChangedhiç çağrılmıyor gibi görünüyor).

Şimdiye kadarki kodum bu:

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, ""));
        }
    }
}

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

Ayrıca, PreferenceFragment tercih değişikliklerini dinlemek için doğru yer mi yoksa bunu Aktivite içinde mi yapmalıyım?


1
Son sorunuza göre her şey Tasarım çerçevenize bağlıdır. Bir MVC veya MVP yaklaşımını kullanmak Android ile yapmak zordur, ancak tüm eylemlerimin parçayı barındıran etkinlikte (Denetleyici) gerçekleşmesine ve parçanın yalnızca kullanıcı arabirimi olmasına izin vermeye çalışıyorum (Görünüm / Sunumcu)
John Shelley

Yanıtlar:


151

Az önce kaydını / kayıt olmanız gerekir inanıyoruz ListenerGözlerinde farklı PreferenceFragmentve işe yarayacak.

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

}

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

Ne yapmak istediğinize bağlı olarak bir dinleyici kullanmanız gerekmeyebilir. Tercihlerdeki değişiklikler SharedPreferencesotomatik olarak yapılır.


Ah, anlıyorum. Bu çalışır. Ama Paylaşılan Tercihleri getPreferenceManager(sizin yaptığınız gibi) veya aracılığıyla getPreferenceScreenmı almalıyım ? Fark ne?
XåpplI'-I0llwlg'I -

Dürüst olmak gerekirse gerçek farkın ne olduğundan emin değilim, belki başka biri buna ağırlık verebilir, başka bir soru için de iyi bir konu olabilir.
00'te antew

2
Tamam, işte bu sorunun cevabı. Kesinlikle işlevsel bir fark yok gibi görünüyor, ancak getPreferenceManagergenellikle tercih edilen seçenektir.
XåpplI'-I0llwlg'I -

ayarlar-tercihi ilk kez oluşturulduğunda, özet saklanan tercih değerine göre ayarlanmamaktadır. Bu nasıl çözülür?
srv_sud

1
@srv_sud keyparametrenin ne olması gerektiğini mi kastediyorsunuz ? Bu denemedim, aşağıdaki Gunnar'ın yanıtında bir örnek vardır: onSharedPreferenceChanged(null, ""). İhtiyaçlarınıza uygun olmayabilir. Belki de güncelleme gerektiren tercih anahtarlarınızı yinelemelisiniz
Jose_GD

24

Antew çözümü iyi çalışıyor, burada Android v11'den itibaren tam bir tercih etkinliğini görebilirsiniz:

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");

    }
}
}

Statik bir sınıfta bu yoktur!
josef

Bunu detaylandırır mısın? Hangi "bu" dan bahsettiğiniz konusunda kesinlikle hiçbir fikrim yok. Cevap 7 yaşında. Android çok değişti.
Gunnar Bernstein

public statik sınıf PrefsFragment statik bir sınıf bildirir ve sonra bunu kendi içinde referans olarak kullanır. Ancak bu mümkün değil, bunu statik bir sınıf içinde kullanamazsınız.
josef

Java'daki statik iç sınıflar kavramını anladığınızdan emin misiniz? Statik iç içe geçmiş bir sınıf, dış sınıfını somutlaştırmadan somutlaştırılabilir. "Bunu" kullanmak gayet iyi. Bu C # değil!
Gunnar Bernstein

Emin değilim, ancak kodu Android Studio'da denedim ve bu konuda şikayet ediyor: "getPreferenceScreen (). GetSharedPreferences (). RegisterOnSharedPreferenceChangeListener (this);". Derlemek için kodu yeniden yazmak zorunda kaldım.
josef

16

Diğer tüm cevaplar doğru. Ancak bu alternatifi daha çok seviyorum çünkü değişikliğe neden olan Preference örneğine hemen sahipsiniz.

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

Doğru, ancak ile onSharedPreferenceChanged ()Preference örneğine kolayca erişebilirsiniz findPreference(key). Belki SharedPreferenceskayıt / kayıt silme olayı nedeniyle tercih edilir?
Jose_GD

2

Bu benim için PreferenceFragment.onCreate () içinden çalıştı

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

1

İşte bunu yapmanın ve olası bellek sızıntılarını önlemenin bir yolu:

@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

Başka bir eksiksiz örnek, böylece resmin tamamını görüyorsunuz.

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

Geçenlerde bir araya kendi koyarak bitmiş PreferenceScreenkullanarak Preferences APIben kendi tam Örnek katkı sağlayacağını düşündüm, .. Bu güncelleme içerir Summaryyeni / değişmiş Değerine yanı sıra Dinleme ve değişikliklere tepki gösteriyor.

PS. Son soruya cevap vermek için: için varsayılan bir değer göstermek için Summaryilk oluşturulduktan sonra PreferenceScreen(önceki değeri herhangi bir değişiklik için), sen olabilir basitçe set android:summaryiçinden, seçtiğiniz bir Değerine preferences.xmldoğrudan dosyanın - ve sonra bir kez orada Değerdeki bir değişikliktir , aşağıdaki Örneğimde bulunan kodu kullanarak otomatik olarak güncellenecektir. Şahsen , Preferencebaş harfim olarak kısa bir açıklama kullanıyorumSummary, Penceremin içinde yer preferences.xmlDeğer kez ve sonra gelmez ilk defa değişti, sadece güncel Değerini gösterir Summary.. o andan itibaren

neyse burada doludur, Örnek:

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() {
    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);

    super.onPause();
}
}


Umarım bu yardımcı olur!
StackOverflow'da oldukça yeni olduğum için herhangi bir olumlu geri bildirim çok takdir edilmektedir;)
Mutlu kodlamalar!


İçinde onPause, super.onPause()dinleyicinin kaydı silinmeden önce mi yoksa sonra mı çağrılmalıdır? Bir fark var mı? Her ikisini de çok sayıda örnekte gördüm
Bryan W

@BryanWalsh Ben de örneklerini gördüğümüz hem ben listerner kaydını düşünüyorum .. şekillerde olur önce çağıran super.onPause();muhtemelen bu konuda gitmek için en iyi yoldur.
Studio2bDesigns

0

Yönteminizde belirtilen Prefernce sınıfını kaldırmanız yeterlidir onResume(). Benim durumumda SwitchPreferencesınıf kullanıyordum , bu nedenle kod şöyle olurdu- 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);

    }

Ardından PrefernceFragmentdeğeri kullanmak istediğiniz aktivitede SharedPreference, değerleri çağırmak ve tetiklemek için nesneyi kullanmanız yeterlidir.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.