Android?Preference 須知
一、理論
?
1.前言
在Android的應用開發中經常會涉及到設置界面的設計開發,為此Android提供了名為Preference的設置處理機制,沿用這種機制的話能省去開發者很多不必要的時間開支。
那Preference究竟是什么呢?看一下你Android手機里的“設置”這個應用就知道了,大體界面如下:
這個設置界面就是通過Preference構建的,可能有些同學會說,這不就是一個普通的LinearLayout嗎?有什么特別的?下面我們就開具體說說什么是Preference。
?
2.什么是Preference?
Preference翻譯過來是“偏愛,愛好”的意思,在Android中Preference是一個具體的類,它代表著一個最基本的UI塊(可以理解為ListView中的一個item),并且顯示在Activity或Fragment內置的ListView上面,如圖1-1中的“聲音”選項,就是一個Preference的UI塊表現(這里為什么要說表現呢?因為Preference本身并不是繼承View的視圖類,它只是代表著一個偏好選項然后通過提供UI塊來展示這些偏好選項)。并且每一個UI塊都會和一個SharePreferences關聯來保存或恢復偏好設置。
?
3.Preference從何而來?
得到Preference的方法有兩種:一種是從Xml文件中獲取,在Xml文件中每一個節點都能指定特定的Preference的子類。另外一種方法就是在代碼中動態的創建。為了處理好Preference與SharePreferences的關聯,Preference類提供了一個Key來作為使用SharePreferences時的Key。
4.Preference的子類們
開關類型:
TwoStatePreference是一個抽象類,它下面的兩個子類CheckBoxPreference和SwitchPreference。
?
彈出框類型:
彈出框類型的都繼承子虛擬類DialogPreference,分別是EditPreference,MultiCheckPreference,ListPreference,MultiSelectListPreference,SeekBarDialogPreference,VolumePreferenc。
?
特殊:
RingtonePreference和SeekBarPreference分別是鈴聲選擇和滑塊。
?
組類型:
組類型都繼承子抽象類PreferenceGroup,其中PreferenceCategory表示分類,PreferenceScreen主要用來表示一個設置界面中的根節點。
5.Preference其他相關類介紹:
GenericInflater:用于解析xml文件
?
PreferenceInflater:繼承自GenericInflater用于解析包含Preference的xml
?
PreferenceActivity:在kk和之前的版本上用于顯示一系列Preference的Header(標頭,用于跳轉到對應的PreferenceFragment),從L開始PreferenceActivity的功能被PreferenceFragment集成了。
?
PreferenceFragment:用ListView來顯示一系列Preference的層次結構。
?
PreferenceManager:用于幫助從xml或代碼中創建Preference的層次結構。
二、實踐
?
1.從xml文件中構建Preference ,主要代碼如下:
----PreferencesFromXml.java----
[java]?view plaincopy
@Override?? ???protected?void?onCreate(BundlesavedInstanceState)?{?? ???????super.onCreate(savedInstanceState);?? ?? ????????? ????????? ???????addPreferencesFromResource(R.xml.preferences);?? ???}?? preferences文件內容如下:
[html]?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>?? ?? <PreferenceScreen?? ???????xmlns:android="http://schemas.android.com/apk/res/android">?? ??? ????<PreferenceCategory?? ???????????android:title="@string/inline_preferences">?? ????????????? ????????<CheckBoxPreference?? ????????????????android:key="checkbox_preference"?? ????????????????android:title="@string/title_checkbox_preference"?? ????????????????android:summary="@string/summary_checkbox_preference"?/>?? ??? ????</PreferenceCategory>?? ????????????????? ????<PreferenceCategory?? ???????????android:title="@string/dialog_based_preferences">?? ??? ????????<EditTextPreference?? ????????????????android:key="edittext_preference"?? ????????????????android:title="@string/title_edittext_preference"?? ????????????????android:summary="@string/summary_edittext_preference"?? ????????????????android:dialogTitle="@string/dialog_title_edittext_preference"?/>?? ????????????????? ????????<ListPreference?? ????????????????android:key="list_preference"?? ????????????????android:title="@string/title_list_preference"?? ????????????????android:summary="@string/summary_list_preference"?? ????????????????android:entries="@array/entries_list_preference"?? ????????????????android:entryValues="@array/entryvalues_list_preference"?? ????????????????android:dialogTitle="@string/dialog_title_list_preference"?/>?? ??? ????</PreferenceCategory>?? ??? ????<PreferenceCategory?? ???????????android:title="@string/launch_preferences">?? ??? ????????<!--?This?PreferenceScreen?tag?servesas?a?screen?break?(similar?to?page?break?? ?????????????in?word?processing).?Like?forother?preference?types,?we?assign?a?key?? ?????????????here?so?it?is?able?to?save?andrestore?its?instance?state.?-->?? ????????<PreferenceScreen?? ????????????????android:key="screen_preference"?? ????????????????android:title="@string/title_screen_preference"?? ????????????????android:summary="@string/summary_screen_preference">?? ????????????? ?????????????? ?????????????????????? ????????????<CheckBoxPreference?? ????????????????????android:key="next_screen_checkbox_preference"?? ????????????????????android:title="@string/title_next_screen_toggle_preference"?? ????????????????????android:summary="@string/summary_next_screen_toggle_preference"?/>?? ????????????????? ????????</PreferenceScreen>?? ??? ????????<PreferenceScreen?? ????????????????android:title="@string/title_intent_preference"?? ????????????????android:summary="@string/summary_intent_preference">?? ??? ????????????<intent?android:action="android.intent.action.VIEW"?? ????????????????????android:data="http://www.android.com"?/>?? ??? ????????</PreferenceScreen>?? ??? ????</PreferenceCategory>?? ????? ????<PreferenceCategory?? ???????????android:title="@string/preference_attributes">?? ????? ????????<CheckBoxPreference?? ????????????????android:key="parent_checkbox_preference"?? ????????????????android:title="@string/title_parent_preference"?? ????????????????android:summary="@string/summary_parent_preference"?/>?? ??? ?????????? ????????<CheckBoxPreference?? ????????????????android:key="child_checkbox_preference"?? ????????????????android:dependency="parent_checkbox_preference"?? ????????????????android:layout="?android:attr/preferenceLayoutChild"?? ????????????????android:title="@string/title_child_preference"?? ????????????????android:summary="@string/summary_child_preference"?/>?? ????????????? ????</PreferenceCategory>?? ????? </PreferenceScreen>?? ?? ?
就是這么簡單,只需要簡單配置一下xml文件,一個設置界面就完成了,上面的xml文件對應的界面如下:
我們來分析一下這個xml文件
首先看它的根節點?PreferenceScreen?它對應的就是PreferenceScreen對象表示這一層次結構的最外層。接著是PreferenceCategory它表示一個分類的開始對應PreferenceCategory對象。在PreferenceCategory里可以看到一些節點如:CheckBoxPreference,EditTextPreference,ListPreference等,都是表示一個設置選項,其對應的也是名字與之相同的類。
?
2.從代碼中構建Preference
代碼如下:
----PreferencesFromCode.java----
?
[java]?view plaincopy
public?classPreferencesFromCode?extends?PreferenceActivity?{?? ??? ????private?static?final?StringPARENT_CHECKBOX_PREFERENCE?=?"parent_checkbox_preference";?? ??? ????@Override?? ????protected?void?onCreate(BundlesavedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ??? ????????PreferenceScreen?root?=getPreferenceManager().createPreferenceScreen(this);?? ????????setPreferenceScreen(root);?? ????????populatePreferenceHierarchy(root);?? ????}?? ??? ????private?voidpopulatePreferenceHierarchy(PreferenceScreen?root)?{?? ?????????? ????????PreferenceCategory?inlinePrefCat?=?newPreferenceCategory(this);?? ???????inlinePrefCat.setTitle(R.string.inline_preferences);?? ????????root.addPreference(inlinePrefCat);?? ??? ?????????? ????????CheckBoxPreference?checkboxPref?=?newCheckBoxPreference(this);?? ????????checkboxPref.setKey("checkbox_preference");?? ???????checkboxPref.setTitle(R.string.title_checkbox_preference);?? ???????checkboxPref.setSummary(R.string.summary_checkbox_preference);?? ???????inlinePrefCat.addPreference(checkboxPref);?? ??? ?????????? ????????SwitchPreference?switchPref?=?newSwitchPreference(this);?? ???????switchPref.setKey("switch_preference");?? ???????switchPref.setTitle(R.string.title_switch_preference);?? ???????switchPref.setSummary(R.string.summary_switch_preference);?? ????????inlinePrefCat.addPreference(switchPref);?? ??? ?????????? ????????PreferenceCategory?dialogBasedPrefCat?=new?PreferenceCategory(this);?? ???????dialogBasedPrefCat.setTitle(R.string.dialog_based_preferences);?? ????????root.addPreference(dialogBasedPrefCat);?? ??? ?????????? ????????EditTextPreference?editTextPref?=?newEditTextPreference(this);?? ???????editTextPref.setDialogTitle(R.string.dialog_title_edittext_preference);?? ???????editTextPref.setKey("edittext_preference");?? ????????editTextPref.setTitle(R.string.title_edittext_preference);?? ???????editTextPref.setSummary(R.string.summary_edittext_preference);?? ???????dialogBasedPrefCat.addPreference(editTextPref);?? ??? ?????????? ????????ListPreference?listPref?=?newListPreference(this);?? ???????listPref.setEntries(R.array.entries_list_preference);?? ???????listPref.setEntryValues(R.array.entryvalues_list_preference);?? ???????listPref.setDialogTitle(R.string.dialog_title_list_preference);?? ????????listPref.setKey("list_preference");?? ???????listPref.setTitle(R.string.title_list_preference);?? ???????listPref.setSummary(R.string.summary_list_preference);?? ???????dialogBasedPrefCat.addPreference(listPref);?? ??? ?????????? ????????PreferenceCategory?launchPrefCat?=?newPreferenceCategory(this);?? ???????launchPrefCat.setTitle(R.string.launch_preferences);?? ????????root.addPreference(launchPrefCat);?? ??? ????????? ? ? ? ?? ?????????? ????????PreferenceScreen?screenPref?=getPreferenceManager().createPreferenceScreen(this);?? ???????screenPref.setKey("screen_preference");?? ???????screenPref.setTitle(R.string.title_screen_preference);?? ???????screenPref.setSummary(R.string.summary_screen_preference);?? ???????launchPrefCat.addPreference(screenPref);?? ??? ????????? ? ? ?? ??? ?????????? ????????CheckBoxPreferencenextScreenCheckBoxPref?=?new?CheckBoxPreference(this);?? ???????nextScreenCheckBoxPref.setKey("next_screen_toggle_preference");?? ???????nextScreenCheckBoxPref.setTitle(R.string.title_next_screen_toggle_preference);?? ???????nextScreenCheckBoxPref.setSummary(R.string.summary_next_screen_toggle_preference);?? ????????screenPref.addPreference(nextScreenCheckBoxPref);?? ??? ?????????? ????????PreferenceScreen?intentPref?=getPreferenceManager().createPreferenceScreen(this);?? ????????intentPref.setIntent(newIntent().setAction(Intent.ACTION_VIEW)?? ???????????????.setData(Uri.parse("http://www.android.com")));?? ???????intentPref.setTitle(R.string.title_intent_preference);?? ???????intentPref.setSummary(R.string.summary_intent_preference);?? ???????launchPrefCat.addPreference(intentPref);?? ??? ?????????? ????????PreferenceCategory?prefAttrsCat?=?newPreferenceCategory(this);?? ???????prefAttrsCat.setTitle(R.string.preference_attributes);?? ????????root.addPreference(prefAttrsCat);?? ??? ?????????? ????????CheckBoxPreference?parentCheckBoxPref?=new?CheckBoxPreference(this);?? ???????parentCheckBoxPref.setTitle(R.string.title_parent_preference);?? ???????parentCheckBoxPref.setSummary(R.string.summary_parent_preference);?? ????????prefAttrsCat.addPreference(parentCheckBoxPref);?? ???????parentCheckBoxPref.setKey(PARENT_CHECKBOX_PREFERENCE);?? ??? ?????????? ?????????? ?????????? ????????TypedArray?a?=?obtainStyledAttributes(R.styleable.TogglePrefAttrs);?? ????????CheckBoxPreference?childCheckBoxPref?=new?CheckBoxPreference(this);?? ???????childCheckBoxPref.setTitle(R.string.title_child_preference);?? ???????childCheckBoxPref.setSummary(R.string.summary_child_preference);?? ????????childCheckBoxPref.setLayoutResource(?? ???????????????a.getResourceId(R.styleable.TogglePrefAttrs_android_preferenceLayoutChild,?? ????????????????????????0));?? ???????prefAttrsCat.addPreference(childCheckBoxPref);?? ????????childCheckBoxPref.setDependency(PARENT_CHECKBOX_PREFERENCE);?? ????????a.recycle();?? ????}?? }?? ?
動態構建Preference的過程是:構建PreferenceScreen,然后構建PreferenceCategory,并往PreferenceCategory中添加需要使用的Preference的子類,然后將PreferenceCategory添加到PreferenceScreen。
上述代碼效果圖如下:
三、Preference實現機制
?
在講機制之前我們來做一個簡單的demo,通過這個demo來直擊Preference的運行現場。
?
demo很簡單,有兩個界面:
MyPreferenceDemo.java (一個activity,顯示從SharePreferences取key為my_demo_key的值)
MySetting.java (一個key為my_demo_key的EditPreference)
關鍵代碼如下:
----MyPreferenceDemo.java
[java]?view plaincopy
public?class?MyPreferenceDemo?extends?Activity?{?? ??? ????private?TextView?mTextView?;?? ????@Override?? ????protected?void?onCreate(BundlesavedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????setContentView(R.layout.activity_main);?? ????????mTextView?=?(TextView)findViewById(R.id.show_preferecne)?;?? ????}?? ??? ????@Override?? ????protected?void?onResume()?{?? ????????super.onResume();?? ????????mTextView.setText(getPreferenceByKey());?? ????}?? ??? ????private?String?getPreferenceByKey()?{?? ????????? ????????String?pref?=?""?;?? ????????pref?=PreferenceManager.getDefaultSharedPreferences(this).getString("my_demo_key","Hello")?;?? ????????return?pref;?? ????}?? ??? ????@Override?? ????public?boolean?onCreateOptionsMenu(Menu?menu){?? ?????????? ????????getMenuInflater().inflate(R.menu.main,?menu);?? ????????return?true;?? ????}?? ??? ????@Override?? ????public?boolean?onOptionsItemSelected(MenuItemitem)?{?? ????????if(item.getItemId()?==?R.id.action_settings){?? ????????????Toast.makeText(this,?"settings",?Toast.LENGTH_LONG).show()?;?? ????????????Intent?intent?=?new?Intent()?;?? ????????????intent.setClass(this,?MySetting.class)?;?? ????????????startActivity(intent)?;?? ????????}?? ????????return?super.onOptionsItemSelected(item);?? ????}?? }?? ?
----MySetting.java
[java]?view plaincopy
public?class?MySetting?extends?PreferenceActivity?{?? ??? ????@Override?? ????protected?void?onCreate(BundlesavedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????? ????????PreferenceScreen?root?=?getPreferenceManager().createPreferenceScreen(this);?? ????????setPreferenceScreen(root);?? ????????populatePreferenceHierarchy(root);?? ????}?? ????? ????private?void?populatePreferenceHierarchy(PreferenceScreenroot)?{?? ????????PreferenceCategory?myCat?=?new?PreferenceCategory(this);?? ????????myCat.setTitle("My?PreferenceDemo");?? ????????root.addPreference(myCat);?? ??? ????????EditTextPreference?editTextPref?=?new?EditTextPreference(this);?? ????????editTextPref.setDialogTitle("please?inputsomething");?? ????????editTextPref.setKey("my_demo_key");?? ????????editTextPref.setTitle("settings");?? ????????editTextPref.setSummary("設置activity中需要顯示的字符串");?? ????????myCat.addPreference(editTextPref);?? ??? ????}?? }?? ?
程序界面如下:
點擊“settings”輸入“這是preference的demo”,然后返回第一個界面,就會顯示 “這是preference的demo”。
?
我們先來看看獲得SharePreferences的這個方法:
?
[java]?view plaincopy
PreferenceManager.getDefaultSharedPreferences(this)??
跟進源代碼發現getDefaultSharedPreferences的實現如下:
[java]?view plaincopy
public?static?SharedPreferencesgetDefaultSharedPreferences(Context?context)??????{?? ????returncontext.getSharedPreferences(getDefaultSharedPreferencesName(context),?? ???????????getDefaultSharedPreferencesMode());?? }?? ?? private?static?StringgetDefaultSharedPreferencesName(Context?context)?{?? ????return?context.getPackageName()?+?"_preferences";?? }?? ?? private?static?intgetDefaultSharedPreferencesMode()?{?? ????return?Context.MODE_PRIVATE;?? }?? 內部其實還是調用了?getSharedPreferences這個方法來獲得SharePreferences,參數name和mode分別是:context.getPackageName() +"_preferences"和?Context.MODE_PRIVATE。
?
接著我們看看我們使用的?EditTextPreference是怎么將字符串保存到SharePreferences的,
?
我們看到在EditTextPreference內部有這么一個回調方法:
?
??
[java]?view plaincopy
@Override?? ???protected?void?onDialogClosed(boolean?positiveResult)?{?? ???????super.onDialogClosed(positiveResult);?? ???????? ???????if?(positiveResult)?{?? ???????????String?value?=?mEditText.getText().toString();?? ???????????if?(callChangeListener(value))?{?? ???????????????setText(value);?? ???????????}?? ???????}?? ???}?? ?
當設置好字符串關閉對話框時這個方法會被回調,獲得輸入的字符串value然后調用settext(value),
?
? ?
[java]?view plaincopy
public?void?setText(String?text)?{?? ???????final?boolean?wasBlocking?=shouldDisableDependents();?? ???????? ???????mText?=?text;?? ???????? ???????persistString(text);?? ???????? ???????final?boolean?isBlocking?=shouldDisableDependents();?? ???????if?(isBlocking?!=?wasBlocking)?{?? ???????????notifyDependencyChange(isBlocking);?? ???????}?? ???}?? ?
我們接著看persistString(text);? 這個方法,首先persist的意思是持久化,那我們可以很容易聯想到本地文件或者數據庫之類的,那這邊到底會把text保存到哪里?我們接著看。
?
?
[java]?view plaincopy
protected?boolean?persistString(String?value)?{?? ?????if?(shouldPersist())?{?? ??????????? ?????????if?(value?==?getPersistedString(null))?{?? ??????????????? ?????????????return?true;?? ?????????}?? ?????????? ?????????SharedPreferences.Editor?editor?=?mPreferenceManager.getEditor();?? ?????????editor.putString(mKey,?value);?? ?????????tryCommit(editor);?? ?????????return?true;?? ?????}?? ?????return?false;?? ?}?? ?
看到這里就就明了了,最終還是將value這個數據保存在了SharePreferences里面。
?
最基本的Preference實現機制就到這里了,總結一句話:
Preference設置屬性的保存還是依賴于SharePreferences。
關于SharePreferences的運行機制,我會在后面在給出。
pdf下載?http://pan.baidu.com/s/1o6p2dYi
原文地址:http://blog.csdn.net/will_captain/article/details/40404523
總結
以上是生活随笔為你收集整理的Android Preference 须知的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。