前篇文章Android ApiDemo示例解析(31):App->Preferences->Launching preferences 中用到了Advanced preferences 中定義的AdvancedPreferences。android
本篇具體介紹AdvancedPreferences, 這個例子稱爲Advanced ,是由於它涉及到了自定義Preference, 並在一個工做線程中刷新某個Preference的值。api
Preference 爲顯示在PreferenceActivity (通常以列表顯示)在某個偏好的基類。有點相似於顯示在Activity中的某個View。Preference 實際存取的是對應在Shared Preferences中一項,而Preference定義的key也就是用來訪問Shared Preferences的key值。ide
和View同樣能夠自定義View,在Android中也能夠自定義Preference,用來顯示管理應用自定義的程序偏好。本例 MyPreference 自定義一個Preference 用來存儲用戶點擊該Preference的次數,類型爲整數,初始值定義爲100。它在advanced_preferences.xml 對應的定義以下:函數
<com.example.android.apis.preference.MyPreference android:key="my_preference" android:title="@string/title_my_preference" android:summary="@string/summary_my_preference" android:defaultValue="100" />
Preference 定義了不少屬性,好比Default Value, dependency, enabled, icon ,key 等等都有對應的方法來操做。而且提供了兩個Listener:PreferenceChangeListener, PreferenceClickListener ,容許應用程序響應Preference值變化事件,或是用戶點擊Preference事件。post
這裏按照MyPreference 代碼順序說明一下如何自定義一個Preference。this
1. 派生於 Preference基類。spa
public class MyPreference extends Preference
2. 和自定義View相似能夠爲自定義Preference 自定義Layout。 MyPreference 使用R.layout.preference_widget_mypreference ,定義很簡單隻有一個TextView ,其id爲mypreference_widget。 通常在構造函數中使用setWidgetLayoutResource爲Preference派生類設置Layout資源。線程
// This is the constructor called by the inflater public MyPreference(Context context, AttributeSet attrs) { super(context, attrs); setWidgetLayoutResource(R.layout.preference_widget_mypreference); }
3. 若有須要爲自定義的Layout中的View 設置屬性,能夠在onBindView(View view)中完成。下面代碼爲TextView設置值爲mClickCounter。rest
@Override protected void onBindView(View view) { super.onBindView(view); // Set our custom views inside the layout final TextView myTextView = (TextView) view.findViewById(R.id.mypreference_widget); if (myTextView != null) { myTextView.setText(String.valueOf(mClickCounter)); } }
4. 若是爲該自定義Preference 在XML定義了初值,好比 MyPreference的初值android:defaultValue=」100″,咱們想在代碼中使用這個初值來初始化變量 mClickCounter 。mClickCounter 類型爲整數,這個變量就是用來保存用戶的按鍵次數的。code
@Override protected Object onGetDefaultValue(TypedArray a, int index) { // This preference type's value type is Integer, so we read the default // value from the attributes as an Integer. return a.getInteger(index, 0); } @Override protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { if (restoreValue) { // Restore state mClickCounter = getPersistedInt(mClickCounter); } else { // Set state int value = (Integer) defaultValue; mClickCounter = value; persistInt(value); } }
5 重載 onSaveInstanceState,onRestoreInstanceState ,這兩個方法是用來臨時保存或是恢復一些變量值。在Preference 調用persistInt,persistBoolean, persistString等以前,preference 對應的值尚未被保存在或是更新在Shared preferences 中,若是這時用戶旋轉屏幕,則形成Activity從新建立,咱們須要在屏幕旋轉時用戶選擇項會保留,可使用 onSaveInstanceState,onRestoreInstanceState來保持一些臨時數據。
@Override protected Parcelable onSaveInstanceState() { /* * Suppose a client uses this preference type without persisting. We * must save the instance state so it is able to, for example, survive * orientation changes. */ final Parcelable superState = super.onSaveInstanceState(); if (isPersistent()) { // No need to save instance state since it's persistent return superState; } // Save the instance state final SavedState myState = new SavedState(superState); myState.clickCounter = mClickCounter; return myState; } @Override protected void onRestoreInstanceState(Parcelable state) { if (!state.getClass().equals(SavedState.class)) { // Didn't save state for us in onSaveInstanceState super.onRestoreInstanceState(state); return; } // Restore the instance state SavedState myState = (SavedState) state; super.onRestoreInstanceState(myState.getSuperState()); mClickCounter = myState.clickCounter; notifyChanged(); }
其中SavedState爲BaseSavedState的子類,這裏不詳細介紹了,而BaseSavedState實現了Parcelable接口,借用Windows平臺上的Serialable,其功能和其它平臺上序列化功能相似。
6. MyPreference響應Click事件,並將按鍵次數存入Shared Preferences 中。
@Override protected void onClick() { int newValue = mClickCounter + 1; // Give the client a chance to ignore this change if they deem it // invalid if (!callChangeListener(newValue)) { // They don't want the value to be set return; } // Increment counter mClickCounter = newValue; // Save to persistent storage (this method will make sure this // preference should be persistent, along with other useful checks) persistInt(mClickCounter); // Data has changed, notify so UI can be refreshed! notifyChanged(); }
Preference使用persistBoolean, persistFloat ,persistInt, persistLong ,persisitString 向Shared Preferences中存儲數據,由於mClickCounter爲整數,因此使用persistInt。 notifyChanged用於通知UI有數據變化。callChangeListener 將會調用註冊過的Preference.OnPreferenceChangeListener 以通知Preference有變化。
再來看看AdvancedPreferences,代碼不是很長,以下:
public class AdvancedPreferences extends PreferenceActivity implements OnSharedPreferenceChangeListener { public static final String KEY_MY_PREFERENCE = "my_preference"; public static final String KEY_ADVANCED_CHECKBOX_PREFERENCE = "advanced_checkbox_preference"; private CheckBoxPreference mCheckBoxPreference; private Handler mHandler = new Handler(); /** * This is a simple example of controlling a preference from code. */ private Runnable mForceCheckBoxRunnable = new Runnable() { public void run() { if (mCheckBoxPreference != null) { mCheckBoxPreference.setChecked(!mCheckBoxPreference.isChecked()); } // Force toggle again in a second mHandler.postDelayed(this, 1000); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the XML preferences file addPreferencesFromResource(R.xml.advanced_preferences); // Get a reference to the checkbox preference mCheckBoxPreference = (CheckBoxPreference)getPreferenceScreen().findPreference( KEY_ADVANCED_CHECKBOX_PREFERENCE); } @Override protected void onResume() { super.onResume(); // Start the force toggle mForceCheckBoxRunnable.run(); // 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); mHandler.removeCallbacks(mForceCheckBoxRunnable); } public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { // Let's do something when my counter preference value changes if (key.equals(KEY_MY_PREFERENCE)) { Toast.makeText(this, "Thanks! You increased my count to " + sharedPreferences.getInt(key, 0), Toast.LENGTH_SHORT).show(); } } }
它實現了OnSharedPreferenceChangeListener,所以能夠用來監聽MyPreference的變化。
Handler ,因爲程序中須要從工做線程中更新Preference的值,而Preference爲UI,不能夠從工做線程中直接更新UI,Handler容許工做線 程來更新UI,後續有詳細介紹。本例每隔1秒將Haunted preference 值變化一次(選中->不選->選中->不選 ..)
registerOnSharedPreferenceChangeListener,unregisterOnSharedPreferenceChangeListener 用來爲SharedPreferences 註冊一個總的Preference 變化事件處理代碼。本例中MyPreference變化時在屏幕上顯示當前按鍵的次數: