73

Như được mô tả here, tôi đang phân lớp PreferenceFragment và hiển thị nó bên trong một Activity. Tài liệu đó giải thích cách nghe các thay đổi ưu tiên here, nhưng chỉ khi bạn phân lớp PreferenceActivity. Vì tôi không làm điều đó, làm thế nào để tôi nghe những thay đổi ưu tiên?Làm thế nào để lắng nghe những thay đổi ưu tiên trong một PreferenceFragment?

Tôi đã thử triển khai OnSharedPreferenceChangeListener trong PreferenceFragment của mình nhưng dường như không hoạt động (onSharedPreferenceChanged dường như không bao giờ được gọi).

Đây là mã của tôi cho đến nay:

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> 

Ngoài ra, tùy chọn PreferenceFragment có phải là nơi thích hợp để nghe các thay đổi tùy chọn hoặc tôi nên thực hiện trong Hoạt động không?

+1

Câu hỏi cuối cùng của bạn tất cả đều phụ thuộc vào khung Thiết kế của bạn. Để sử dụng một cách tiếp cận MVC hoặc MVP là khó để làm với Android nhưng tôi cố gắng để cho tất cả các hành động của tôi diễn ra trong hoạt động (Controller) lưu trữ các mảnh, và mảnh là ui chỉ (View/Presenter) –

Trả lời

131

Tôi tin rằng bạn chỉ cần đăng ký/hủy đăng ký Listener trong số PreferenceFragment và nó sẽ hoạt động.

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

} 

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

Tùy thuộc vào những gì bạn muốn làm bạn có thể không cần sử dụng người nghe. Các thay đổi đối với tùy chọn được tự động cam kết là SharedPreferences.

+0

Ah, tôi xem. Điều đó hoạt động. Nhưng tôi có nên nhận SharedPreferences qua 'getPreferenceManager' (như bạn đã làm) hay' getPreferenceScreen'? Có gì khác biệt? –

+0

Thành thật mà nói tôi không chắc sự khác biệt thực sự là gì, có lẽ ai đó có thể cân nhắc về nó, nó có thể là một chủ đề tốt cho một câu hỏi khác nữa. – antew

+2

Được rồi, [ở đây] (http://stackoverflow.com/q/13618335/963396) là câu trả lời cho câu hỏi đó. Có vẻ như hoàn toàn không có sự khác biệt về chức năng, nhưng 'getPreferenceManager' thường là tùy chọn ưa thích. –

21

Các giải pháp của antew hoạt động tốt, ở đây bạn có thể thấy một hoạt động ưu tiên đầy đủ dành cho Android v11 trở đi:

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

    } 
} 
} 
12

Tất cả các câu trả lời khác là chính xác. Nhưng tôi thích điều này thay thế tốt hơn bởi vì bạn ngay lập tức có trường hợp Tùy chọn gây ra thay đổi.

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

Đúng, mặc dù trong 'onSharedPreferenceChanged()' bạn có thể truy cập cá thể Preference một cách dễ dàng bằng 'findPreference (key)'. Có lẽ cách 'SharedPreferences' được ưa thích hơn vì điều đăng ký/không đăng ký? –

2

này làm việc cho tôi từ PreferenceFragment.onCreate()

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

Một ví dụ hoàn chỉnh, do đó bạn nhìn thấy toàn bộ bức tranh.

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); 
     } 
    } 
} 
Các vấn đề liên quan