小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

從零開始

 容有無 2014-11-12

第5章 設(shè)置(Settings)


本章不同于通常網(wǎng)絡(luò)上經(jīng)常使用的SharedPreference,而是從底層了解Preference。FAQ QQ群213821767


應(yīng)用程序通常包括允許用戶修改應(yīng)用程序的特性和行為的設(shè)置功能。例如,一些應(yīng)用程序允許用戶指定通知是否啟用或指定多久使用云同步數(shù)據(jù)。如果你想要為你的應(yīng)用程序提供設(shè)置,你應(yīng)該使用Android的Preference APIs來構(gòu)建統(tǒng)一的接口。本章的主角就是Preference,下面先讓我們看一下圖5-1:


:


圖5-1 這是android短信息應(yīng)用程序的設(shè)置界面截圖。它使用就是就是Preference


5.1 概述


相比使用View對象來構(gòu)建用戶接main,設(shè)置是構(gòu)建Preference的子類。一個Preference對象是構(gòu)建一個單一設(shè)置的一個部分。每一個Preference作為一個item在list并為用戶修改設(shè)置提供了適當(dāng)?shù)慕缑?。例如,一個CheckBoxPreference創(chuàng)建一個用于顯示checkbox的list item,ListPreference創(chuàng)建一個選擇列表來顯示一個對話框的item。每一個Preference其實都以鍵值對的形式保存在你應(yīng)用程序的SharedPreferences文件中。當(dāng)用戶改變設(shè)置時,系統(tǒng)會更新SharedPreferences文件中的鍵值對。我們只需要讀取文件中的設(shè)置數(shù)據(jù)即可。SharedPreferences支持以下數(shù)據(jù)類型的保存:


Boolean


Float


Int


Long


String


String Set


因為你的應(yīng)用程序設(shè)置界面是使用Preference對象構(gòu)建的而不是view,你需要使用Activity或Fragment的子類來顯示設(shè)置列表:


◆    如果你的應(yīng)用程序支持android 3.0以下版本,你必須使用PreferenceActivity類來構(gòu)建。


◆    如果高于或等于android 3.0版本,你可以使用PreferenceFragment。當(dāng)然你屏幕如果足夠大的話你還是可以使用PreferenceActivity創(chuàng)建雙面板布局來顯示多組設(shè)置


5.1.1 Preference


你應(yīng)用中的每一個設(shè)置都代表一個Preference對象。每一個Preference的子類包含一組核心的屬性,如允許你指定設(shè)置的標(biāo)題和默認(rèn)值這樣的屬性。每一個子類也提供自己的屬性和用戶界面。就想上面圖5-1那樣,每一個設(shè)置都是List View中的一個item,也是一個Preference對象。常見的Preference如下:


CheckBoxPreference


用checkbox顯示一個item的設(shè)置是否為打開或關(guān)閉。他保存的是boolean值,true表示選中


ListPreference


以單選按鈕列表的形式打開一個對話框,保存的值能支持任意類型


EditTextPreference


使用EditText打開一個對話框。保存的值為一個String。


5.2 在XML中定義Preferences


雖然你可以在運行時實例化新的Preference對象,但你也可以在XML中用Preference層級對象來定義。使用XML定義設(shè)置是首選,因為XML文件結(jié)構(gòu)更容易閱讀的并且更新也很簡單。此外,你的應(yīng)用程序的設(shè)置通常是預(yù)先確定的,但你仍然可以在運行時修改它們。每一個Preference子類都能使用XML節(jié)點來匹配聲明。如<CheckBoxPreference>。你必須在項目的res/xml目錄下保存這種XML文件。盡管你可以任意命名你的文件名字,但建議使用preferences.xml,方便以后識別自己寫的東西。注意如果你想要為你的設(shè)置創(chuàng)建多面板布局,那你需要為每一個fragment創(chuàng)建單獨的XML文件。


根節(jié)點的XML文件必須是一個< PreferenceScreen >元素。在這個元素中你可以添加每個Preference。每個你添加在< PreferenceScreen >元素下的子節(jié)點顯示為單一列表項的設(shè)置。如代碼清單5-1所示:



按 Ctrl+C 復(fù)制代碼
按 Ctrl+C 復(fù)制代碼

 



代碼清單5-1


在上面的例子中有一個CheckBoxPreference和一個ListPreference。這兩個items包含以下三個屬性:


◆android:key


這個屬性是必須的,對于一個preferences 來說是一個持久的數(shù)據(jù)值。當(dāng)在SharedPreferences中保存這個Setting值時這個指定唯一的key(一個字符串)是被系統(tǒng)使用的。但某些特殊情況,如preferences是一個PreferenceCategory或 PreferenceScreen,或者是一個XML中<Intent>調(diào)用時,又或者是一個Fragment顯示時(用android:fragment屬性),以上這些特殊情況下,這個key就不是必須的了。


◆android:title


為設(shè)置提供了一個用戶可見的名稱。


◆android:defaultValue


這指定初始值,系統(tǒng)應(yīng)該建立在SharedPreferences文件。你應(yīng)該為所有設(shè)置提供一個默認(rèn)值。


關(guān)于其他更多屬性,請直接查看Preference文檔。


 


圖 5-2 根據(jù)title的設(shè)置分類

1. 通過指定<PreferenceCategory>節(jié)點的分類 

2. 通過使用android:title指定title分類.


當(dāng)你的列表設(shè)置超過大約10項,您可能想通過添加標(biāo)題定義分組設(shè)置或在一個單獨的屏幕顯示這些組。


5.2.1創(chuàng)建設(shè)置組(groups)


如果你列出10個或更多的設(shè)置,用戶可能會有些頭疼。這樣我們就可以使用分組。以下有兩種分組方法:


◆使用titles


◆使用subscreens


1. 使用titles


如果你想要根據(jù)標(biāo)題來提供分界線,請使用PreferenceCategory如代碼清單5-2所示:



復(fù)制代碼

<PreferenceScreen xmlns:android="http://schemas./apk/res/android">
    <PreferenceCategory 
        android:title="@string/pref_sms_storage_title"
        android:key="pref_key_storage_settings">
        <CheckBoxPreference
            android:key="pref_key_auto_delete"
            android:summary="@string/pref_summary_auto_delete"
            android:title="@string/pref_title_auto_delete"
            android:defaultValue="false"... />
        <Preference 
            android:key="pref_key_sms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_sms_delete"... />
        <Preference 
            android:key="pref_key_mms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_mms_delete" ... />
    </PreferenceCategory>
    ...
</PreferenceScreen>

復(fù)制代碼

 



代碼清單5-2


2. 使用subscreens


 


如果你想要放置設(shè)置組到一個subscreen中,請使用PreferenceScreen如圖5-3和代碼清單5-3:



 


圖 5-3



復(fù)制代碼

<PreferenceScreen  xmlns:android="http://schemas./apk/res/android">
    <!--打開一個subscreen -->
    <PreferenceScreen
        android:key="button_voicemail_category_key"
        android:title="@string/voicemail"
        android:persistent="false">
        <ListPreference
            android:key="button_voicemail_provider_key"
            android:title="@string/voicemail_provider" ... />
        <!--打開另一個嵌套的subscreen -->
        <PreferenceScreen
            android:key="button_voicemail_setting_key"
            android:title="@string/voicemail_settings"
            android:persistent="false">
            ...
        </PreferenceScreen>
        <RingtonePreference
            android:key="button_voicemail_ringtone_key"
            android:title="@string/voicemail_ringtone_title"
            android:ringtoneType="notification" ... />
        ...
    </PreferenceScreen>
    ...
</PreferenceScreen>

復(fù)制代碼

 



代碼清單5-3


5.2.2使用Intents


某些情況下, 你可能想要一個preference item來打開不同的activity而不是設(shè)置屏幕,就像一個web瀏覽器來查看一個web頁面。當(dāng)用戶選擇一個preference item時可以調(diào)用Intent來啟動。方法就是添加一個<intent>節(jié)點到<Preference>節(jié)點中。如代碼清單5-4所示:




<Preference android:title="@string/prefs_web_page" >
    <intent android:action="android.intent.action.VIEW"
            android:data="http://www." />
</Preference>


 



代碼清單5-4


 


你能使用以下屬性創(chuàng)建隱式和顯式的intents:


android:action


如同setAction()方法一樣設(shè)置action


android:data


如同setData()方法一樣設(shè)置data


◆android:mimeType


如同setType()方法一樣設(shè)置MIME類型


◆android:targetClass


如同setComponent()方法一樣設(shè)置組件類名


◆android:targetPackage


如同setComponent()方法一樣設(shè)置組件包名


5.3 創(chuàng)建一個Preference Activity


為了在Acitivity中顯示你的設(shè)置,你可以繼承PreferenceActivity類。這是擴展于傳統(tǒng)Activity的一個類,它基于Preference對象層級來顯示一個設(shè)置列表。當(dāng)用戶做出一個改變時PreferenceActivity能自動保存與每一個Preference相關(guān)的設(shè)置。注意:如果在3.0或以上系統(tǒng)版本中,你應(yīng)該使用PreferenceFragment。最重要的是要記住,你在onCreate()回調(diào)期間沒有加載一個視圖的布局。而是調(diào)用addPreferencesFromResource()來添加你定義的XML文件。例如代碼清單5-5所示:



復(fù)制代碼

public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}

復(fù)制代碼

 



代碼清單5-5


只要用戶修改preference,系統(tǒng)將改變保存到一個默認(rèn)的SharedPreferences文件。


5.4 使用Preference Fragments


如果你在android3.0或更高版本上開發(fā),你應(yīng)該使用PreferenceFragment來顯示Preference  對象列表。你不應(yīng)該在使用PreferenceActivity了。因為Fragments提供更為靈活的應(yīng)用程序結(jié)構(gòu)如代碼清單5-6所示:



復(fù)制代碼

public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
    ...
}

復(fù)制代碼

 



代碼清單5-6


然后你能吧這個fragment添加到Activity,如代碼清單5-7所示:



復(fù)制代碼

public class SettingsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();
    }
}

復(fù)制代碼

 



代碼清單5-7


注意:一個PreferenceFragment沒有它自己的Context對象。如果你需要一個Content對象,你能調(diào)用getActivity()方法。然而,當(dāng)fragment沒有附加到activity中或者activity聲明周期結(jié)束時分離后,你使用getActivity()返回的將是null。


5.5 Setting的默認(rèn)值


    你創(chuàng)建preferences可能是為你的應(yīng)用程序定義一些重要的行為,所以當(dāng)用戶第一次打開你的應(yīng)用程序時,為每一個Preference相關(guān)的SharedPreferences 文件初始化默認(rèn)值是必要的。首先你必須為每一個Preference對象指定一個默認(rèn)值,你可以在XML文件中使用android:defaultValue屬性。例如代碼清單5-8所示:



按 Ctrl+C 復(fù)制代碼
按 Ctrl+C 復(fù)制代碼

 



代碼清單5-8


然后,在Main Activity里的onCreate()方法中調(diào)用一次setDefaultValues(),如代碼清單5-9所示:




PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);


 



代碼清單5-9


在onCreate()方法的最開始就可以執(zhí)行此方法,因為可能你的界面需要依據(jù)默認(rèn)值來設(shè)置一個屬性。這個方法中有三個參數(shù):


1.應(yīng)用程序的Context


2.Preference XML資源ID


3.這個boolean表示是否多次設(shè)置默認(rèn)值,當(dāng)然大部分情況下默認(rèn)值一般我們只需要設(shè)置一次,就傳false即可


5.6 使用Preference Headers


在少數(shù)情況下,如用首次屏幕顯示的時候,你可能想要讓用戶先設(shè)置一些配置屬性。在android3.0或更高版本系統(tǒng)下,你可以使用新的“headers”功能來代替以前的subscreens的嵌套。使用headers步驟如下:


1. 單獨的每組設(shè)置作為獨立PreferenceFragment的實例。即,每組設(shè)置需要一個單獨的XML文件。


2. 創(chuàng)建一個XML頭文件,其中列出了每個設(shè)置組和聲明這fragment包含相應(yīng)的設(shè)置列表。


3. 擴展PreferenceActivity類來托管您的設(shè)置。


4. 實現(xiàn)onBuildHeaders()回調(diào)用來指定頭文件。


一個很棒的好處是,PreferenceActivity使用這個設(shè)計自動給出了雙欄布局如圖5-4大屏幕上運行時。


即使你的應(yīng)用程序支持Android 3.0以上的版本,你也可以使用PreferenceFragment來構(gòu)建應(yīng)用程序用于較新的設(shè)備


 


圖 5-4 使用headers的雙面板布局


1. headers使用一個xml heanders文件定義


2.每一組設(shè)置通過PreferenceFragment來定義,并且在<header>節(jié)點中指定


 


圖 5-5 這是一個手機設(shè)備,當(dāng)一個item選中時候,會調(diào)用PreferenceFragment


5.6.1創(chuàng)建headers文件


每一組設(shè)置你都可以在<preference-headers>跟節(jié)點中指定一個<header>節(jié)點,如代碼清單5-10所示:



復(fù)制代碼

<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas./apk/res/android">
    <header 
        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
        android:title="@string/prefs_category_one"
        android:summary="@string/prefs_summ_category_one" />
    <header 
        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
        android:title="@string/prefs_category_two"
        android:summary="@string/prefs_summ_category_two" >
        <!—這個鍵值對可以當(dāng)成一個fragment的參數(shù)-->
        <extra android:name="someKey" android:value="someHeaderValue" />
    </header>
</preference-headers>

復(fù)制代碼

 



代碼清單5-10


使用android:fragment屬性,每一個header聲明一個PreferenceFragment實例,當(dāng)用戶選擇這個header時就會打開這個PreferenceFragment。<extras>節(jié)點允許你通過鍵值對的形式傳參,一般是使用Bundle。Fragment通過調(diào)用getArguments()來得到參數(shù)。關(guān)于參數(shù)的用途比較常見的就是為每一個組重用相同的PreferenceFragment子類并且使用參數(shù)還是制定你將要載入哪一個preferences XML文件。例如,下面是一個fragment,它被多個設(shè)置組重用,下面代碼清單5-11中在XML中使用了<extra>節(jié)點,key為“settings”:



復(fù)制代碼

public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        String settings = getArguments().getString("settings");
        if ("notifications".equals(settings)) {
            addPreferencesFromResource(R.xml.settings_wifi);
        } else if ("sync".equals(settings)) {
            addPreferencesFromResource(R.xml.settings_sync);
        }
    }
}

復(fù)制代碼

 



代碼清單5-11


5.6.2顯示headers


為了顯示preference headers, 你必須實現(xiàn)onBuildHeaders()回調(diào)方法并且調(diào)用loadHeadersFromResource()如代碼清單5-12所示:




public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.preference_headers, target);
    }
}


 



代碼清單5-12


當(dāng)用戶從headers列表中選擇一個item時,系統(tǒng)會打開相關(guān)的PreferenceFragment。注意當(dāng)使用preference headers時候,你的PreferenceActivity 子類不需要onCreate()方法,因為這個activity的任務(wù)僅僅是載入headers而已。


5.6.3老版本中支持Preference header


如果你的應(yīng)用程序既支持3.0以下的版本,也支持3.0以上的版本,要么3.0以上我們使用headers能提供雙面板布局。低于3.0的版本我們就可以添加額外的preferences XML但里面不是使用<header>而是使用<Preference>節(jié)點了。但每一個<Preference>都發(fā)送一個intent到PreferenceActivity。例如讓我們先看下3.0或以上版本的代碼清單5-13中(res/xml/preference_headers.xml):



復(fù)制代碼

<preference-headers xmlns:android="http://schemas./apk/res/android">
    <header 
        android:fragment="com.example.prefs.SettingsFragmentOne"
        android:title="@string/prefs_category_one"
        android:summary="@string/prefs_summ_category_one" />
    <header 
        android:fragment="com.example.prefs.SettingsFragmentTwo"
        android:title="@string/prefs_category_two"
        android:summary="@string/prefs_summ_category_two" />
</preference-headers>

復(fù)制代碼

 



代碼清單5-13


然后讓我們再看下3.0以下版本的代碼清單5-14中(res/xml/preference_headers_legacy.xml):



復(fù)制代碼

<PreferenceScreen xmlns:android="http://schemas./apk/res/android">
    <Preference 
        android:title="@string/prefs_category_one"
        android:summary="@string/prefs_summ_category_one"  >
        <intent 
            android:targetPackage="com.example.prefs"
            android:targetClass="com.example.prefs.SettingsActivity"
            android:action="com.example.prefs.PREFS_ONE" />
    </Preference>
    <Preference 
        android:title="@string/prefs_category_two"
        android:summary="@string/prefs_summ_category_two" >
        <intent 
            android:targetPackage="com.example.prefs"
            android:targetClass="com.example.prefs.SettingsActivity"
            android:action="com.example.prefs.PREFS_TWO" />
    </Preference>
</PreferenceScreen>

復(fù)制代碼

 



代碼清單5-14


因為android3.0中支持<preference-headers>,僅在android3.0或更高版本中系統(tǒng)會在PreferenceActivity中調(diào)用onBuildHeaders()方法。當(dāng)然如果用戶的系統(tǒng)不是3.0(HONEYCOMB)的你就必須調(diào)用preference_headers_legacy.xml,然后調(diào)用addPreferencesFromResource()來載入xml文件。例如代碼清單5-15所示:



復(fù)制代碼

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
 
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        //低于3.0版本載入legacy preferences headers
        addPreferencesFromResource(R.xml.preference_headers_legacy);
    }
}
 
// 高于或等于3.0版本會調(diào)用此方法
@Override
public void onBuildHeaders(List<Header> target) {
   loadHeadersFromResource(R.xml.preference_headers, target);
}

復(fù)制代碼

 



代碼清單5-15


剩下的3.0以下版本就是通過處理Intent來識別哪個preference文件要被加載到Activity中來。所以需要檢索intent的action并與在preference XML<intent>下已知action字符串比較,如代碼清單5-16所示:



復(fù)制代碼

final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
...
 
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
 
    String action = getIntent().getAction();
    if (action != null && action.equals(ACTION_PREFS_ONE)) {
        addPreferencesFromResource(R.xml.preferences);
    }
    ...
 
    else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        // 載入3.0以下版本的legacy preferences文件
        addPreferencesFromResource(R.xml.preference_headers_legacy);
    }
}

復(fù)制代碼

 



代碼清單5-16


注意連續(xù)調(diào)用addPreferencesFromResource()會堆疊所有的preferences到一個單獨的列表中,所以確保他只調(diào)用一次,把它寫到else-if的條件分支下。


5.7 讀取Preferences


默認(rèn)的,所有你應(yīng)用中的preferences會保存到一個文件中,你可以調(diào)用靜態(tài)方法PreferenceManager.getDefaultSharedPreferences()來獲得你保存的preferences。它將返回一個SharedPreferences對象包含所有你在PreferenceActivity中使用的Preference對象的鍵值對。例如,下面代碼清單5-17教你如何讀取:




SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");


 



代碼清單5-17


5.7.1監(jiān)聽Preference的改變


有些情況下你可能想只要一個preferences改變你就想得到通知。當(dāng)任意一個preferences發(fā)生改變時,為了取得一個回調(diào),我們可以實現(xiàn)SharedPreference.OnSharedPreferenceChangeListener這個接口并通過SharedPreferences.registerOnSharedPreferenceChangeListener()來注冊監(jiān)聽。這個接口只有一個回調(diào)方法,就是onSharedPreferenceChanged()你很容易就找到。如代碼清單5-18所示:



復(fù)制代碼

public class SettingsActivity extends PreferenceActivity
                              implements OnSharedPreferenceChangeListener {
    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
    ...
 
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key.equals(KEY_PREF_SYNC_CONN)) {
            Preference connectionPref = findPreference(key);
            // 為選中的值設(shè)置用戶描述摘要。
            connectionPref.setSummary(sharedPreferences.getString(key, ""));
        }
    }
}

復(fù)制代碼

 



代碼清單5-18


這個例子中,onSharedPreferenceChanged()方法會檢測改變的設(shè)置是否為一個已知的preference key。如果是就會調(diào)用findPreference()來獲得Preference對象,并且這是改變后的對象你可以做你想做的事情,這里我們設(shè)置了一個摘要用于當(dāng)用戶選中時給出提示信息。其實這是一個比較好的方法,特別是多個被選中時,你可以通過現(xiàn)有的API讓用戶知道他們做了些什么并得到反饋。還有請注意記得在Activity聲明周期中的onPause()和 onResume()方法中注冊于注銷你的監(jiān)聽,如代碼清單5-19所示:



復(fù)制代碼

@Override
protected void onResume() {
    super.onResume();
    getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
}
 
@Override
protected void onPause() {
    super.onPause();
    getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
}

復(fù)制代碼

 



代碼清單5-19


5.8 管理網(wǎng)絡(luò)的使用


從Android4.0開始,系統(tǒng)的設(shè)置應(yīng)用程序允許用戶能看到他們的應(yīng)用程序在前臺和后臺使用了多少網(wǎng)絡(luò)數(shù)據(jù)。用戶對于個別Apps能關(guān)閉使用后臺數(shù)據(jù)。為了避免用戶關(guān)閉你的程序從后臺訪問數(shù)據(jù)的功能,你應(yīng)該使用數(shù)據(jù)連接有效并允許用戶通過你應(yīng)用程序的設(shè)置來完善你應(yīng)用程序的數(shù)據(jù)使用。例如你可能允許用戶控制你的APP多久同步一次數(shù)據(jù),是否你的app僅在Wifi情況下才更新和下載,漫游情況下如何處理等。這樣的好處是給用戶更精準(zhǔn)的控制你的程序使用多少數(shù)據(jù),有這樣的精準(zhǔn)控制,用戶就不會在系統(tǒng)設(shè)置中直接把你的應(yīng)用訪問數(shù)據(jù)的功能給關(guān)掉。一旦你在PreferenceActivity 中添加了必要的preferences來控制你App的數(shù)據(jù),并養(yǎng)成了這種寫程序的習(xí)慣,那接下來我很樂意給你說明一下,你應(yīng)該在manifest文件中添加一個intent filter名字為ACTION_MANAGE_NETWORK_USAGE,如代碼清單5-20所示:




<activity android:name="SettingsActivity" ... >
    <intent-filter>
       <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
       <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>


 



代碼清單5-20


這個intent filter表明了這個activity告訴系統(tǒng)我能控制這個應(yīng)用程序的數(shù)據(jù)使用。因此,當(dāng)用戶在設(shè)置應(yīng)用中檢查你app使用了多少數(shù)據(jù)時,一個App設(shè)置按鈕便可用了,你點擊它會啟動PreferenceActivity然后讓用戶在精確控制你的app數(shù)據(jù)使用情況。


5.9 構(gòu)建自定義的Preference


Android框架包含各種各樣的Preference子類允許你構(gòu)建自己的UI。然而你可能發(fā)現(xiàn)一個設(shè)置沒有好的內(nèi)置方案,如一個number picker或date picker。在這種情況下你需要創(chuàng)建自定義的preference,你需要繼承Preference類。當(dāng)然擴展Preference類后有一些重要的事情要做:


◆當(dāng)用戶選擇設(shè)置的時候指定用戶接口


◆在適當(dāng)?shù)那闆r下保存setting的值


◆當(dāng)進入我們的View時,使用當(dāng)前值或默認(rèn)值初始化Preference


◆當(dāng)被系統(tǒng)請求時,提供默認(rèn)值


◆如果Preference提供它自己的UI(如一個對話框),保存和恢復(fù)狀態(tài)并處理生命周期的改變 。


5.9.1指定用戶界面


如果你直接擴展Preference類,當(dāng)用戶選擇一個item時,你需要實現(xiàn)onClick()用來定義action。其實大部分情況下就是直接繼承的DialogPreference顯示對話框的形式,這樣簡化的程序。如果你繼承了DialogPreference,你必須在類的構(gòu)造函數(shù)中調(diào)用setDialogLayoutResourcs()來指定布局。如代碼清單5-21所示:



復(fù)制代碼

public class NumberPickerPreference extends DialogPreference {
    public NumberPickerPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        
        setDialogLayoutResource(R.layout.numberpicker_dialog);
        setPositiveButtonText(android.R.string.ok);
        setNegativeButtonText(android.R.string.cancel);
        
        setDialogIcon(null);
    }
    ...
}

復(fù)制代碼

 



代碼清單5-21


5.9.2保存設(shè)置的值


你可以在任意時刻調(diào)用Preference類的persist*()方法來保存一個值,如設(shè)置的值為int,那么就使用persistInt()。這個方法用在對話框關(guān)閉的時候調(diào)用比較好,它會給用戶一個提示。當(dāng)點擊positive按鈕時,你就可以保存新的值。如代碼清單5-22所示:



復(fù)制代碼

@Override
protected void onDialogClosed(boolean positiveResult) {
    // 當(dāng)用戶選擇OK時,保存新的值
    if (positiveResult) {
        persistInt(mNewValue);
    }
}

復(fù)制代碼

 



代碼清單5-22


在上面這個例子中,mNewValue是一個類成員變量,并且是int型的。


5.9.3初始化當(dāng)前值


當(dāng)系統(tǒng)添加你的Preference 到屏幕時,它會調(diào)用onSetInitialValue() 來通知你的值是否是已經(jīng)存在的值。如果不存在,這個調(diào)用會提供一個默認(rèn)值。onSetInitialValue()方法通過一個boolean值來表明一個值是否已經(jīng)被存儲了。如果為true,你應(yīng)該把存儲的值給取出來,你可以使用getPersistedInt()這樣類似的方法取值。如果restorePersistedValue這個參數(shù)的值為false,那么你就可以使用第二個默認(rèn)值參數(shù)了,如代碼清單5-23所示:



復(fù)制代碼

@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
    if (restorePersistedValue) {
        // 恢復(fù)狀態(tài)
        mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
    } else {
        // 從xml屬性中設(shè)置默認(rèn)狀態(tài)
        mCurrentValue = (Integer) defaultValue;
        persistInt(mCurrentValue);
    }
}

復(fù)制代碼

 



代碼清單5-23


請注意這里當(dāng)restorePersistedValue為true時不能使用參數(shù)自帶的defaultValue,因為它的值為null,只有當(dāng)restorePersistedValue為false時才能使用。


5.9.4提供一個默認(rèn)值


如果Preference的實例指定一個默認(rèn)值(使用android:defaultValue屬性),那么當(dāng)Preference實例化對象時為了取得默認(rèn)值,系統(tǒng)會調(diào)用onGetDefaultValue()方法。你必須實現(xiàn)這個方法,這樣在系統(tǒng)保存默認(rèn)值到SharedPreferences的時候才能正確處理。例如代碼清單5-24所示:



@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
    return a.getInteger(index, DEFAULT_VALUE);
}


 


代碼清單5-24


方法參數(shù)提供你需要的一切:數(shù)組屬性和你需要檢索的android:defaultValue的索引位置,原因你必須實現(xiàn)這個方法來提取默認(rèn)值的屬性,因為您必須指定一個本地屬性的默認(rèn)值,以防值是未定義的。


5.9.5保存和恢復(fù)Preference的狀態(tài)


就像一個在布局中的View,你的Preference子類負(fù)責(zé)保存和恢復(fù)它的狀態(tài),以防止activity和fragment被重新啟動。妥善保存和恢復(fù)你Preference類的狀態(tài),你必須實現(xiàn)生命周期中的onSaveInstanceState()和onRestoreInstanceState()回調(diào)。Preference的狀態(tài)可以通過Parcelable接口實現(xiàn)。Android框架提供這樣一個對象,你可以作為入口點定義你對象的狀態(tài),比如Preference.BaseSavedState類。定義你Preference保存狀態(tài),你應(yīng)該繼承Preference.BaseSavedState類。你需要重寫一些方法來定義CREATOR對象。對于大部分應(yīng)用程序,你可以直接復(fù)制一下實現(xiàn)并做一些簡單的改變即可,如代碼清單5-25所示:



復(fù)制代碼

private static class SavedState extends BaseSavedState {
    int value;
 
    public SavedState(Parcelable superState) {
        super(superState);
    }
 
    public SavedState(Parcel source) {
        super(source);
        // 獲得當(dāng)前preference的值
        value = source.readInt();  
    }
 
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        // 寫入preference的值
        dest.writeInt(value);  
    }
 
    public static final Parcelable.Creator<SavedState> CREATOR =
            new Parcelable.Creator<SavedState>() {
 
        public SavedState createFromParcel(Parcel in) {
            return new SavedState(in);
        }
 
        public SavedState[] newArray(int size) {
            return new SavedState[size];
        }
    };
}

復(fù)制代碼

 



代碼清單5-25


下面是具體運用在onSaveInstanceState()和andonRestoreInstanceState()中的過程,如代碼清單5-26所示:



復(fù)制代碼

@Override
protected Parcelable onSaveInstanceState() {
    final Parcelable superState = super.onSaveInstanceState();
    // 檢查Preference是否被保存過
    if (isPersistent()) {
        //不需要保存實例狀態(tài),因為它是持久化的,使用父類狀態(tài)
        return superState;
    }
 
    // 創(chuàng)建自定義的BaseSavedState實例
    final SavedState myState = new SavedState(superState);
    // 使用類成員變量賦值
    myState.value = mNewValue;
    return myState;
}
 
@Override
protected void onRestoreInstanceState(Parcelable state) {
    //檢查我們在onSaveInstanceState中是否保存過狀態(tài)
    if (state == null || !state.getClass().equals(SavedState.class)) {
        // 沒有保存狀態(tài),調(diào)用父類的方法
        super.onRestoreInstanceState(state);
        return;
    }
 
    // 強制轉(zhuǎn)換到自定義的BaseSavedState
    SavedState myState = (SavedState) state;
    super.onRestoreInstanceState(myState.getSuperState());
    
    // 應(yīng)用它的值到UI,以恢復(fù)UI狀態(tài)
    mNumberPicker.setValue(myState.value);
}

復(fù)制代碼

 



代碼清單5-26


 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多