Android 4.4 Settings 應用分析

分類:編程 時間:2017-02-15

一次偶然要在設置裏面增加一個菜單,需要修改到settings_headers.xml 文件(res/layout/xml) 文件,所以就覺得要看一下這個流程.

分析android 源碼的時候導入單個應用的時候一般是會有很多錯誤的,因為需要導入系統編譯之後生成的jar包才能消除eclipse 裏面的哪些紅色xx.

1.Settings的UI

圖一

圖2

 

 

2.流程分析

從AndroidManifest.xml 中查看

<category android:name="android.intent.category.LAUNCHER" /> 知道Settings.Java 是這個應用入口activity.

 

Settings 繼承了PreferenceActivity .他的布局文件是settings_headers.xml

這個文件裏面都是這些header,效果可以參考上面的效果圖1和圖2.

 

<!-- WIRELESS and NetworkS  分類-->

    <header android:id="@+id/wireless_section"

android:title="@string/header_category_wireless_networks" />

 

    <!-- Sim management 普通項-->

    <header

android:id="@+id/sim_settings"

android:icon="@drawable/ic_settings_dualsim"

        android:fragment="com.mediatek.gemini.SimManagement"

android:title="@string/gemini_sim_management_title" />

 

 

com.android.settings.Settings.java 這個activity 是通過回調onBuildHeaders方法來加載進入應用之後的第一個布局文件的,然後調用 loadHeadersFromResource(R.xml.settings_headers, headers);

來解析 文件.

onBuildHeaders 和loadHeadersFromResource 方法都是父類PreferenceActivity 的方法.

 

Settings.java 重寫onBuildHeaders 方法的實現的源碼如下:

/**

     * Populate the activity with the top-level headers.

     */

@Override

    public void onBuildHeaders(List<Header> headers) {

        if (!onIsHidingHeaders()) {

PDebug.Start("loadHeadersFromResource");

loadHeadersFromResource(R.xml.settings_headers, headers);

PDebug.End("loadHeadersFromResource");

updateHeaderList(headers);

        }

    }

 

loadHeadersFromResource 方法就是解析settings_headers.xml 文件並保持相關的數據到List<Header> headers 裏面.

Header 定義很多變量來和settings_headers.xml 裏面節點一一對應,

public long id = HEADER_ID_UNDEFINED;

public int titleRes;

public CharSequence title;

public String fragment;

public Bundle fragmentArguments;

public Intent intent;

public Bundle extras;

………

 

 

通過跟蹤Setting.java 的父類(PreferenceActivity)的繼承關系知道他其實也是一個ListActivity.java ,全部的設置項也是使用ListView來顯示的.

 

HeaderAdapter這個適配類是Setting.java 的內部類,它會判斷之後來加載對應的view和數據來顯示UI.

 

HeaderAdapter已經定義了4中類型的View 類型

static final int HEADER_TYPE_CATEGORY = 0;//用來分類的

static final int HEADER_TYPE_NORMAL = 1;//常規項

static final int HEADER_TYPE_SWITCH = 2;//開關項

static final int HEADER_TYPE_BUTTON = 3;//按鈕項

 

前3種應該都見過,為了讓大家看到第4項,我把稍微修改了一下我的HeaderAdapter源碼,也就是上面圖2中的security 選項.

HeaderAdapter 的getHeaderType 方法決定了配置在settings_headers.xml 裏面的header的類型.

HeaderAdapter 的getView 方法根據header的類型 來加載對應的布局文件.

 

static int getHeaderType(Header header) {

if (header.fragment == null && header.intent == null) {

return HEADER_TYPE_CATEGORY;

} else if (header.id == R.id.WIFI_settings || header.id == R.id.bluetooth_settings

                     || header.id == R.id.hotknot_settings) {

return HEADER_TYPE_SWITCH;

} else if (header.id == R.id.security_settings) {

return HEADER_TYPE_BUTTON;

} else {

return HEADER_TYPE_NORMAL;

}

        }

 

getView 方法內容太多,這裏就不貼出來了.

但要註意的是在getView方法裏面,當發現一個header 的類型是button的時候也會給header 的button增加一個onclick事件的,這個事件和header本事的onHeaderClick 是沒有沖突的,因為2者不受同一個控件.

 

那麽每一個header 是如果響應點擊操作的呢.這個就要看Setting.java的onHeaderClick 方法了, onHeaderClick 方法會調用父類的onHeaderClick方法來打開相關的應用,其父類是根據我們配置在settings_headers.xml裏面的fragment和intent 來打開相對應的activity的.

 

Setting.java -- onHeaderClick

public void onHeaderClick(Header header, int position) {

boolean revert = false;

        if (header.id == R.id.account_add) {

revert = true;

        }

 

super.onHeaderClick(header, position);

 

        if (revert && mLastHeader != null) {

highlightHeader((int) mLastHeader.id);

        } else {

mLastHeader = header;

        }

    }

 

PreferenceActivity -- onHeaderClick

public void onHeaderClick(Header header, int position) {

        if (header.fragment != null) {

if (mSinglePane) {

Log.d(TAG, "onHeaderClick, single pane and startWithFragment.");

int titleRes = header.breadCrumbTitleRes;

int shortTitleRes = header.breadCrumbShortTitleRes;

if (titleRes == 0) {

titleRes = header.titleRes;

shortTitleRes = 0;

}

startWithFragment(header.fragment, header.fragmentArguments, null, 0,

                        titleRes, shortTitleRes);

} else {

Log.d(TAG, "onHeaderClick, multiple pane and switchToHeader.");

switchToHeader(header);

}

        } else if (header.intent != null) {

Log.d(TAG, "onHeaderClick, start activity with header intent.");

startActivity(header.intent);

        }

    }

 


Tags:

文章來源:


ads
ads

相關文章
ads

相關文章

ad