Android進階——Preference詳解之Preference系的基本應用和管理(二)

引言

前面簡單描述下了Preference的家族構成和基本知識,相信對於Preference早已不會陌生,肯定也躍躍欲試了吧,這篇文章就給大家總結下Preference、PreferenceActivity、PreferenceGroup、RingtonePreference的普通應用和管理,還有通過一些測試來驗證一些機制和原理。

一、PreferenceActivity

1、PreferenceActivity概述

PreferenceActivity是一個抽象類,繼承於ListActivity,以列表形式視圖來展現界面,加載的整個View也是基於ListActivity中那個ListView的,其最主要的優勢在於添加Preference後可讓其狀態持久化儲存(通過SharedPreferences,一般存儲在/data/data//shared_prefs文件夾下的默認名爲“app package name”+”_preferences.xml”的文件裏),比如說用戶勾選CheckBox後退出應用,下一次進入到這一界面時候,對應的是CheckBox依然是被勾選狀態,如果要實現這樣的機制,我們自己也可以實現,但是沒有必要,因爲Android已經替我們實現了,就是我們的這一系列的主角——Preference,Preference會自動地替我們去保存這些狀態對應的值到對應的SharedPreferences文件裏,而當我們每次啓動的時候Acitivity(PreferenceActivity)會自動根據key去獲取相關數據,完成用戶界面的更新。我們手機當中的系統設置就是及其典型的Preference的應用,也正是由於工作中需要去客製化Settings,纔有了這一系列的文章。
這裏寫圖片描述
上圖是我們定製的Settings模塊中的對應的部分SharedPreferences。關於Preference對應的SharedPreferences往往很容易被我們忽視兩點

並非我們第一次打開相應界面之後就會自動創建對應的SharedPreferences文件,而是在我們改變了原有狀態時候<喎�"/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxwPjxzdHJvbmc+sqK3x8v509C1xFByZWZlcmVuY2W8sMbk19PA4La8u+G0tL2oo6y99r321eu21NDo0qq8x8K817TMrLXEUHJlZmVyZW5jZTwvc3Ryb25nPqGjPC9wPg0KPGgyIGlkPQ=="2preferenceactivity的初始化">2、PreferenceActivity的初始化

PreferenceActivity其實和普通的Activity本質上來說區別不大,只不過多了些自動去讀取SharedPrefrences的值來更新界面和其他一些邏輯,所以初始化本質上來說並無很大的區別,但是與普通Activity的layout不同,PreferenceActivity的layout我們可以理解成爲兩個部分:其他View和一個id爲android.R.id.list的ListView,那麼我們可以理解成爲當我們在onCreate方法裏先調用setContentView完成整個Activity的View的構建layout文件裏必須包含id爲android.R.id.list的listView,否則會報E/AndroidRuntime: Caused by: java.lang.RuntimeException: Your content must have a ListView whose id attribute is ‘android.R.id.list’),再調用addPreferencesFromResource來完成Preference界面的構建;當然也可以只調用addPreferencesFromResource方法。

1、繼承PreferenceActivity實現具體業務類,重寫相關生命週期方法

1
2
3
4
5
6
7
8
9
<code class="hljs java">public class MainActivity extends PreferenceActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            addPreferencesFromResource(R.xml.demo_preference);
        }
        ...
    }</code>

2、通過addPreferencesFromResource(xml資源id)加載靜態xml資源文件 或者 完全通過代碼構造對象再動態添加

res文件夾下新建xml文件夾,再在xml文件中新建對應的xml資源,xml資源類似我們在使用普通Activity時的layout文件,PreferenceActivity獨特之處在於並不是使用普通的layout文件,而是使用res下xml文件夾下的xml資源文件

res/xml/demo_preference.xml

1
2
3
4
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<preferencescreen xmlns:android="http://schemas.android.com/apk/res/android">
    <checkboxpreference android:key="key_checkbox_preference" android:summary="Some summay for CheckBoxPreference" android:title="The Title Of CheckBoxPreference">
</checkboxpreference></preferencescreen></code>

也可通過代碼去構造對象,添加容器之後再調用setPreferenceScreen(PreferenceScreen preferenceScreen)把容器對象設置到Activity上

1
2
3
4
5
6
7
8
9
<code class="hljs cs">private void createPreference(){
        PreferenceScreen preferenceScreen = this.getPreferenceManager().createPreferenceScreen(this);//先構建PreferenceScreen對象得到一個佈局容器
        this.setPreferenceScreen(preferenceScreen);//設置容器
        CheckBoxPreference checkBoxPreference=new CheckBoxPreference(this);//構建一個子Preference,待添加到容器中
        checkBoxPreference.setKey(CHECKBOXPRERENCE_KEY);//設置key
        checkBoxPreference.setTitle("The Title Of CheckBoxPreference");//設置title
        checkBoxPreference.setSummary("Some summay for CheckBoxPreference");
        preferenceScreen.addPreference(checkBoxPreference);//添加到容器中
    }</code>

二、Preference的使用

前一篇文章我們講述了Preference家族的基類(接下來我們所要介紹的其他子類Preference一定是繼承了他的所有屬性也可以理解成都是在繼承他所展示的UI效果及交互功能的基礎上升級的)而且Preference可以實例化,那麼我們就可以把他看成對應的一個組件,其實和我們熟悉的TextView一樣,所以我們需要使用的時候第一步肯定是先得到他的對象——而構造對象我們都可以通過兩種方式:通過其對應的構造方法或者其他方法通過xml映射(或許說法不夠準確),接着第二步PreferenceActivity的初始化,再接着根據業務設置相關監聽。

1、構造Preference容器和Preference對象

前面Android進階——Preference詳解之初識Preference及Preference系(一)已經講過PreferenceScreen只能作爲top-level節點,而構造對象我們都可以通過兩種方式:通過其對應的構造方法或者其他方法通過映射xml(或者講法不夠準確)

res/xml/test_preference.xml

1
2
3
4
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<preferencescreen android:key="using_categories_in_root_screen" android:summary="Using Preference Categories" android:title="Categories" xmlns:android="http://schemas.android.com/apk/res/android">
    <preference android:key="key_prerence" android:summary="Preference Demo" android:title="Preferece">
</preference></preferencescreen></code>

2、初始化PreferenceActivity和設置相關監聽

常見的Preference的事件有兩個:setOnPreferenceClickListeneronPreferenceChange

設置Preference點擊監聽
1
2
3
4
5
6
7
<code class="hljs java"> preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                //當接收到Click事件之後觸發
                return true;
            }
        });</code>
設置Preference對應的SharedPrefernces值監聽
1
2
3
4
5
6
7
<code class="hljs java">preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                //如果值改變了我們可以通過監聽這個事件來處理
                return true;
            }
        });</code>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<code class="hljs java">@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);//activity_main裏必須存在id爲android.R.id.list的ListView否則報E/AndroidRuntime:  Caused by: java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list'
        addPreferencesFromResource(R.xml.test_preference);
        mContext=getApplicationContext();
        preference=findPreference(PREFERENCE_KEY);
        preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                //如果值改變了我們可以通過監聽這個事件來獲取新值
                Toast.makeText(mContext, String.format("Preference的值爲%s", newValue),Toast.LENGTH_LONG).show();
                return true;
            }
        });
        //設置Preference的點擊事件監聽
        preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                //當接收到Click事件之後觸發
                Toast.makeText(mContext, "Preference Clicked",Toast.LENGTH_LONG).show();
                return true;
            }
        });
    }</code>

這裏寫圖片描述

3、Preference的常用xml屬性

xml屬性說明
android:iconPreference的icon
android:summary副標題、說明(小字體顯示)
android:title標題
android:key對應的SharedPrefrences的key值
android:layoutPreferenceActivity的佈局文件即如果設置了這個屬性則會覆蓋原來的UI
android:fragment應用在PreferenceActivity中時,當用戶點擊這個Preference時,啓動一個新的Fragment
android:enabled設置Preference是否可用,false陰影狀態不可操作
android:orderPreference的排序,整數類型如”100”
android:persistenttrue時,系統會幫助我們去保存該設置,即使重啓後依然能記憶之前的設置,這也是所謂的持久化 。這裏 將 android:persistent設置爲False,表明不需要讓系統去做持久化,開發者系統通過自己的方式去實現持久化。
android:selectablePreference是否可選,false可以點擊但無響應
android:shouldDisableView當View disabled的時候是否Preference也一樣Disabled.
android:widgetLayout自定義Preference用到給子Preference定義佈局。
1
2
3
4
5
6
7
8
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<preferencescreen android:title="PreferenceScreen" xmlns:android="http://schemas.android.com/apk/res/android">
<preferencecategory android:key="key_prerence" android:summary="Preference Categories Summary" android:title="Preference Categories">
    <checkboxpreference android:icon="@mipmap/ic_launcher" android:key="key_chkpreference" android:summary="CheckboxPreference summary" android:title="CheckBoxPreferenceCheckBoxPreferenceCheckBoxPreferenceCheckBoxPreference">
    <preference android:icon="@mipmap/ic_red_launcher" android:key="key_pre" android:layout="@layout/activity_main" android:title="Preference">
    <edittextpreference android:icon="@mipmap/ic_blue_launcher" android:key="key_edtkpreference" android:summary="EditPreference summary" android:title="EditPreference">
</edittextpreference></preference></checkboxpreference></preferencecategory>
</preferencescreen></code>

這裏寫圖片描述

4、Preference的xml文件中的常用標籤intentextra

在xml文件的Preference標籤中,我們可以添加intent來爲我們快速實現一種意圖,比如說快速打開一個網頁,或者快速啓動一個Activity等等,還可以使用extraintent標籤加參數來傳遞參數(再通過getIntent().getStringExtra(“key”)來獲取)。

點擊這個Preference則會自動去調用瀏覽器打開http://www.hao123.com網頁

1
2
3
4
5
<code class="hljs xml">    <preference android:key="key_pref_intent" android:title="Click me open the web">
        <intent android:action="android.intent.action.VIEW" android:data="http://www.hao123.com">
        <!--可以通過<extra>傳附加信息getIntent().getStringExtra("reused_key") -->
        <extra android:name="key" android:value="value">
    </extra></intent></preference></code>

啓動指定類

1
2
3
4
5
6
<code class="hljs xml"> <preference android:title="PREFERENCE TITLE">
        <!-- android:targetPackage是應用程序的包名,而android:targetClass的路徑在子包下的類 -->
        <!-- android:targetPackage設置爲子包,運行時則找不到Activity -->
        <intent android:action="ACTION_A_INTENT" android:targetclass="com.crazy.training.ui.MainActivity" android:targetpackage="com.crazy.training">
        </intent>
    </preference></code>

三、PreferenceScreen和PreferenceCategory

PreferenceScreen和PreferenceCategory沒有新增的屬性,所有屬性全部繼承自Preference。其中PreferenceScreen作爲頂級容器,PreferenceCategory作爲次級容器(類似於SQL Group by功能暫且這麼理解吧),雖然他們也是可以單獨使用的,但是並不能響應onPreferenceClickonPreferenceChange事件。

佈局和MainActivity的代碼依然很簡單和前面類似

1
2
3
4
5
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<preferencescreen android:title="PreferenceScreen" xmlns:android="http://schemas.android.com/apk/res/android">
<preferencecategory android:key="key_prerence" android:summary="Preference Categories Summary" android:title="Preference Categories">
</preferencecategory>
</preferencescreen></code>

這裏寫圖片描述

1
2
3
4
5
6
7
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<preferencescreen android:title="PreferenceScreen" xmlns:android="http://schemas.android.com/apk/res/android">
<preferencecategory android:key="key_prerence" android:summary="Preference Categories Summary" android:title="Preference Categories">
    <checkboxpreference android:icon="@mipmap/ic_launcher" android:key="key_chkpreference" android:summary="CheckboxPreference summary" android:title="CheckBoxPreference">
    <edittextpreference android:icon="@mipmap/ic_blue_launcher" android:key="key_edtkpreference" android:summary="EditPreference summary" android:title="EditPreference">
</edittextpreference></checkboxpreference></preferencecategory>
</preferencescreen></code>

這裏寫圖片描述

四、RingtonePreference的應用

RingtonePreference起作用就是供我們選擇系統鈴聲的,除了Preference共有的屬性外還新增了自己的幾個獨特屬性。

新增屬性說明
android:ringtoneType鈴聲類型:ringtone、notification、all、alarm
android:showDefault布爾值是否顯示默認鈴聲
android:showSilent布爾值是否顯示靜音

應用也很簡單,與Preference大同小異(注意看圖)

1
2
3
4
5
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<preferencescreen android:key="using_categories_in_root_screen" android:summary="Using Preference Categories" android:title="Categories" xmlns:android="http://schemas.android.com/apk/res/android">
    <ringtonepreference android:key="key_prerence" android:summary="RingPreference Summary" android:title="RingPreferece Title">
 
</ringtonepreference></preferencescreen></code>

這裏寫圖片描述

五、Preference的管理

Preference的管理主要包含Preference的創建添加移除尋找特定Preference,Preference並沒有直接提供相關替換的方法。

1、創建Preference

主要是通過各自對應Preference的構造方法或者直接在xml文件中定義來創建對應的Preference

2、addPreference添加Preference

添加只要是就是調用PreferenceGroup的addPreference(Preference preference)方法 來添加至容器PreferenceGroup。

3、findPreference尋找特定Preference

對於PreferenceActivityfindPreference(key)方法,我們只需要知道key值就可以找到同一xml文件下相應的Preference,勿需考慮層級和嵌套關係
這裏寫圖片描述

4、removePreference或removeAll移除Preference

對於PreferenceGroupremovePreference(Preference preference)removeAll()方法,都是針對某個PreferenceGroup來處理的,所以我們必須考慮層級嵌套關係,可以分爲兩步:先找到PreferenceGroup和要刪除的Preference,再調用PreferenceGroup的removePreference執行刪除動作。

首先這是我們的佈局

1
2
3
4
5
6
7
8
9
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<preferencescreen android:key="key_manage_prefs" xmlns:android="http://schemas.android.com/apk/res/android">
    <preferencecategory android:key="key_category" android:title="PreferenceCategory">
        <edittextpreference android:key="key_edtprefs" android:title="EditTextPreference">
        <preferencescreen android:key="key_child_prefscreen" android:title="Child PreferenceScreen">
            <checkboxpreference android:key="key_checkbox" android:title="CheckBoxPreference">
        </checkboxpreference></preferencescreen>
    </edittextpreference></preferencecategory>
</preferencescreen></code>

測試主體代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<code class="hljs java">public class MainActivity extends PreferenceActivity {
 
    private Context mContext;
    private Preference preference;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.test_preference);
 
        //removePreferenceByKey();
        mContext=getApplicationContext();
        preference=findPreference("key_checkbox_child");//只要是同一個xml文件下的所有Preference都能通過key直接找到
        preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                Toast.makeText(mContext, String.format("Preference的值爲%s", newValue),Toast.LENGTH_LONG).show();
                return true;
            }
        });
 
        preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                Toast.makeText(mContext, "Preference Clicked",Toast.LENGTH_LONG).show();
                //getFragmentManager().beginTransaction().replace(android.R.id.content,new MainFragment()).commit();
                return false;
            }
        });
    }
        private void removePreferenceByKey(){
        /*PreferenceGroup preferenceGroup=(PreferenceGroup)findPreference("key_category");//先找到PreferenceGroup
        Preference preference=findPreference("key_edtprefs");//再找到要刪除的Preference*/
        /*(PreferenceGroup)findPreference("key_child_prefscreen").removePreference(findPreference("key_checkbox_child"));//執行刪除key爲key_checkbox_child的Preference**/
        getPreferenceScreen().removePreference(findPreference("key_category"));//刪除掉key_category及對應節點下的所有節點
        //ERROR//getPreferenceScreen().removePreference(findPreference("key_edtprefs"));//無效,因爲getPreferenceScreen獲得的是當前的頂級容器,而key_edtprefs不是它的直接字節點
        ////((PreferenceGroup)findPreference("key_category")).removeAll();//僅刪除掉key_category下對應Preference節點下的所有子節點
    }</code>

這裏寫圖片描述

小結

這篇文章主要介紹了Preference家族樹中頂級成員和次級成員的應用和簡單原理的說明,也基本把幾乎所有相關的知識點都涉及了,Preference的基本語法都是一樣的,區別在於各自不同的特性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章