一、前言
任何App都會存在設置界面,如果開發者利用普通控件並綁定監聽事件保存設置,這一過程會非常的枯燥,而且耗時。我們可以看到Android系統的設置界面里面的選項如此之多,是不是都是這樣開發的呢?其實不然,Android已經給我們提供了專門設計這一功能的技術,叫應用程序首選項,今天我們將學習如何使用他們來開發配置界面以及功能。
二、准備工作
首先需要理解的就是我們設置界面還是需要控件的,但是我們所使用的控件不在是普通的控件,下面我們來簡單的介紹下我們需要知道的控件。
CheckBoxPreference:用來實現勾選的項目,在SharedPreference中保存為bool類型。
EditTextPreference:用來實現字符輸入的項目,在SharedPreference中保存為字符串類型。
ListPreference:用來實現提供一列數據供選擇的項目,在SharedPreference中保存為字符串類型。
PreferenceActivity:首選項活動。
PreferenceCategory:用來實現將首選項進行分類。
PreferenceScreen:用於在另一個新的屏幕上對首選項進行分組。
除了以上的還有其它的這里就不意義例舉了。
三、正文
1.顯示一個簡單的首選項
首先我們需要打開MainActivity並將繼承的基類改成PreferenceActivity,然后將SetContentView改成AddPreferencesFromResource,具體的代碼如下所示:
1 protected override void OnCreate(Bundle bundle) 2 { 3 base.OnCreate(bundle); 4 AddPreferencesFromResource(Resource.Layout.Main); 5 }
讀者也可以嘗試不修改而直接顯示,當然一定會報錯。
修改好了代碼我們打開Main.axml並將其中的所有xml刪除,改寫成如下所示:

1 <?xml version="1.0" encoding="utf-8"?> 2 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> 3 <PreferenceCategory 4 android:title="配置分類1"> 5 <CheckBoxPreference 6 android:key="PREF_CHECK_BOX" 7 android:title="Check Box Preference" 8 android:defaultValue="true" /> 9 </PreferenceCategory> 10 <PreferenceCategory 11 android:title="配置分類2"> 12 <EditTextPreference 13 android:key="PREF_EDIT_BOX" 14 android:title="Edit Text Preference" 15 android:dialogMessage="please input" 16 android:defaultValue="test" /> 17 </PreferenceCategory> 18 <PreferenceCategory 19 android:title="配置分類3"> 20 <ListPreference 21 android:title="List Preference" 22 android:key="listChoice" 23 android:entries="@array/ListText" 24 android:entryValues="@array/ListValue" 25 android:summary="choice one item" /> 26 </PreferenceCategory> 27 <PreferenceCategory 28 android:title="配置分類4"> 29 <PreferenceScreen 30 android:title="子配置"> 31 <CheckBoxPreference 32 android:key="PREF_CHECK_BOX_1" 33 android:title="Check box" 34 android:defaultValue="true" /> 35 </PreferenceScreen> 36 <PreferenceScreen 37 android:title="打開新的意圖"> 38 <intent 39 android:action="android.settings.DISPLAY_SETTINGS" /> 40 </PreferenceScreen> 41 </PreferenceCategory> 42 </PreferenceScreen>
一部分簡單的,筆者就不多做介紹了。主要是看這段xml代碼:
1 <PreferenceScreen 2 android:title="打開新的意圖"> 3 <intent 4 android:action="android.settings.DISPLAY_SETTINGS" /> 5 </PreferenceScreen>
其中ListPreference中的entries和entryValue資源如下所示(Strings.xml中):
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <string name="Hello">Hello World, Click Me!</string> 4 <string name="ApplicationName">PreferenceScreen</string> 5 <string-array name="ListText"> 6 <item>First</item> 7 <item>Second</item> 8 <item>Third</item> 9 </string-array> 10 <string-array name="ListValue"> 11 <item>VFirst</item> 12 <item>VSecond</item> 13 <item>VThird</item> 14 </string-array> 15 </resources>
我們知道了PreferenceScreen會打開一個新的界面去顯示在它內部的首選項,但是內部是一個intent則表示打開指定action的活動,就如同startActivity一樣,這樣的有點就是有助於我們將某些我們需要的設置,但是在系統中已經存在這個設置,我們就可以通過這種方式將其鏈接過去。下面我們運行項目,將可以看到如下的圖像:
相信有些筆者會感覺這有什么的,顯示的效果跟普通的控件一樣。因為它本身就是利用了普通的控件,當然也不會白利用,因為在內部它已經幫你做好了一大推事情,在這個界面上的每個選項它都已經自動保存進了SharedPreference中,而不需要你去一個一個的綁定事件,然后保存。如果我們需要讀取這些配置只需要通過PreferenceManager的GetDefaultSharedPreferences獲取ISharedPreference類型的對象后通過Get<類型>方法讀取即可,他們的key自然就是控件的android:key屬性的值。這樣我們就節省了不少時間了。
2.監聽首選項更改
雖然我們已經可以讀取配置的值,但是實際的應用中並不是所有的設置都是在下次才啟用。有可能有些設置修改完之后就要修改當前的功能。比如通過設置關閉某個功能,那么在這個設置選擇下去的同時app也需要立即將對應的功能關閉。這時候我們就要監聽對應的事件,而我們只需要實現ISharedPreferencesOnSharedPreferenceChangeListener接口即可,下面為該接口的代碼:
1 public interface ISharedPreferencesOnSharedPreferenceChangeListener : IJavaObject, IDisposable 2 { 3 void OnSharedPreferenceChanged(ISharedPreferences sharedPreferences, string key); 4 }
其中我們可以看到只要實現一個方法,並且該方法的第二個參數是進行修改的選項的android:key的值,通過key我們就可以在第一個參數中獲取修改后的值,這里還需要注意的是要根據情況選擇對應類型的Get方法。
筆者為了節省時間,所以我們依然是利用上節的項目,在MainActivity中實現該接口。
代碼如下所示:
1 public void OnSharedPreferenceChanged(ISharedPreferences sharedPreferences, string key) 2 { 3 string value = ""; 4 switch (key) 5 { 6 case "PREF_CHECK_BOX": 7 { 8 if (sharedPreferences.GetBoolean(key, false)) 9 value = "true"; 10 else 11 value = "false"; 12 } 13 break; 14 case "PREF_EDIT_BOX": 15 { 16 value = sharedPreferences.GetString(key, ""); 17 } 18 break; 19 case "listChoice": 20 { 21 value = sharedPreferences.GetString(key, ""); 22 } 23 break; 24 } 25 Toast.MakeText(this, key + "的值改變為" + value, ToastLength.Short).Show(); 26 }
筆者僅僅只是根據情況獲取對應的值后通過Toast顯示出來,完成了上面這些還不夠,我們還需要將其進行注冊,所以我們需要利用RegisterOnSharedPreferenceChangeListener和UnregisterOnSharedPreferenceChangeListener方法,下面為具體的代碼:
1 protected override void OnResume() 2 { 3 base.OnResume(); 4 PreferenceManager.GetDefaultSharedPreferences(this).RegisterOnSharedPreferenceChangeListener(this); 5 } 6 7 protected override void OnPause() 8 { 9 base.OnPause(); 10 PreferenceManager.GetDefaultSharedPreferences(this).UnregisterOnSharedPreferenceChangeListener(this); 11 }
這里提醒下讀者,筆者在查看《c#開發Android應用實戰》一書中后,采用該書上面的方法,但是監聽事件一直不會被執行,所以參考了Android方面的書籍,而采用了上面的方法。
我們重新運行程序,修改一個項目后將會出現以下的結果:
3.新平台下的應用程序首選項
下面我們將學習Android 3.0后的應用程序首選項如何實現,以開發能夠兼容平板和手機的設置界面。這節筆者建議大家重新創建一個項目,並且Android SDK的版本要在3.0或以上才可以。
首先我們需要設計新的應用程序首選項的xml代碼,筆者的代碼如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> 3 <header 4 android:fragment="preferencefragmentstudy.FirstPreferenceFragment" 5 android:title="FirstFragment" 6 android:summary="the first framgnet" /> 7 <header 8 android:fragment="preferencefragmentstudy.SecondPreferenceFragment" 9 android:title="SecondFragment" 10 android:summary="the second fragment"></header> 11 </preference-headers>
可以看到這里的xml標簽在上面是從來沒有使用過的,而每個header都是一個鏈接,會鏈接到由android:fragment指定的碎片,筆者要注意下fragment的路徑是項目名稱的小寫加類名,如果前面是解決方案的大寫會打不開。並且MainActivity還是繼承自PreferenceActivity,只是我們這里不再重寫OnCreate而是需要重寫OnBuildHeaders方法並調用LoadHeadersFromResource加載上面的xml資源,筆者的代碼如下所示:
1 [Activity(Label = "PreferenceFragmentStudy", MainLauncher = true, Icon = "@drawable/icon")] 2 public class MainActivity : PreferenceActivity 3 { 4 public override void OnBuildHeaders(System.Collections.Generic.IList<PreferenceActivity.Header> target) 5 { 6 LoadHeadersFromResource(Resource.Xml.XMLFile2, target); 7 } 8 }
為了節約時間,另外兩個PreferenceFragment都采用同一個設計,下面為xml的代碼:
1 <?xml version="1.0" encoding="utf-8"?> 2 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> 3 <PreferenceCategory 4 android:title="配置分類1"> 5 <CheckBoxPreference 6 android:key="PREF_CHECK_BOX" 7 android:title="Check Box Preference" 8 android:defaultValue="true" /> 9 </PreferenceCategory> 10 </PreferenceScreen>
這里我們可以看到熟悉的標簽了,下面我們開始設計PreferenceFragment,他們的代碼分別如下所示:
1 public class FirstPreferenceFragment : PreferenceFragment 2 { 3 public override void OnCreate(Bundle bundle) 4 { 5 base.OnCreate(bundle); 6 AddPreferencesFromResource(Resource.Xml.XMLFile1); 7 } 8 }
[Activity(Label = "SecondPreferenceFragment")] public class SecondPreferenceFragment : PreferenceFragment { public override void OnCreate(Bundle bundle) { base.OnCreate(bundle); AddPreferencesFromResource(Resource.Xml.XMLFile1); } }
每個PreferenceFragment都可以單獨使用第二節的技術,下面我們查看最后運行的結果:
點中第一之后:
利用該技術可以在需要大量配置選項的時候能夠有條不紊的設計並歸類。