一次偶然要在設置里面增加一個菜單,需要修改到settings_headers.xml 文件(res/layout/xml) 文件,所以就覺得要看一下這個流程.就做一下筆記,語言組織能力不行啊.
分析Android 源碼的時候導入單個應用的時候一般是會有很多錯誤的,因為需要導入系統編譯之后生成的jar包才能消除eclipse 里面的哪些紅色xx.
1.Settings的UI
?
?
2.流程分析
從AndroidManifest.xml 中查看
<category android:name="android.intent.category.LAUNCHER" /> 知道Settings.java 是這個應用入口activity.
?
Settings 繼承了PreferenceActivity .他的布局文件是settings_headers.xml
這個文件里面都是這些header,效果可以參考上面的效果圖1和圖2.
Xml代碼??
<!--?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 方法的實現的源碼如下:
Java代碼??
/**??????*?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 類型
Java代碼??
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源碼(見getview方法的中的有//add的部分),也就是上面圖2中的security 選項.
HeaderAdapter 的getHeaderType 方法決定了配置在settings_headers.xml 里面的header的類型.
HeaderAdapter 的getView 方法根據header的類型 來加載對應的布局文件.
Java代碼??
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方法里面,當發現一個header 的類型是button的時候也會給header 的button增加一個onclick事件的,這個事件和header本事的onHeaderClick 是沒有沖突的,因為2者不受同一個控件.
Java代碼??
@Override?????????public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{?????????????HeaderViewHolder?holder;?????????????Header?header?=?getItem(position);?????????????int?headerType?=?getHeaderType(header);?????????????Log.d("zhangle","getHeaderType"?+?header.title??+?"?headerType="?+?headerType);?????????????View?view?=?null;???????????????if?(convertView?==?null)?{?????????????????holder?=?new?HeaderViewHolder();?????????????????switch?(headerType)?{?????????????????????case?HEADER_TYPE_CATEGORY:?????????????????????????view?=?new?TextView(getContext(),?null,?????????????????????????????????android.R.attr.listSeparatorTextViewStyle);?????????????????????????holder.title?=?(TextView)?view;?????????????????????????break;???????????????????????case?HEADER_TYPE_SWITCH:?????????????????????????view?=?mInflater.inflate(R.layout.preference_header_switch_item,?parent,?????????????????????????????????false);?????????????????????????holder.icon?=?(ImageView)?view.findViewById(R.id.icon);?????????????????????????holder.title?=?(TextView)?????????????????????????????????view.findViewById(com.android.internal.R.id.title);?????????????????????????holder.summary?=?(TextView)?????????????????????????????????view.findViewById(com.android.internal.R.id.summary);?????????????????????????holder.switch_?=?(Switch)?view.findViewById(R.id.switchWidget);?????????????????????????break;???????????????????????case?HEADER_TYPE_BUTTON:?????????????????????????view?=?mInflater.inflate(R.layout.preference_header_button_item,?parent,?????????????????????????????????false);?????????????????????????holder.icon?=?(ImageView)?view.findViewById(R.id.icon);?????????????????????????holder.title?=?(TextView)?????????????????????????????????view.findViewById(com.android.internal.R.id.title);?????????????????????????holder.summary?=?(TextView)?????????????????????????????????view.findViewById(com.android.internal.R.id.summary);?????????????????????????holder.button_?=?(ImageButton)?view.findViewById(R.id.buttonWidget);?????????????????????????holder.divider_?=?view.findViewById(R.id.divider);?????????????????????????break;???????????????????????case?HEADER_TYPE_NORMAL:?????????????????????????view?=?mInflater.inflate(?????????????????????????????????R.layout.preference_header_item,?parent,?????????????????????????????????false);?????????????????????????holder.icon?=?(ImageView)?view.findViewById(R.id.icon);?????????????????????????holder.title?=?(TextView)?????????????????????????????????view.findViewById(com.android.internal.R.id.title);?????????????????????????holder.summary?=?(TextView)?????????????????????????????????view.findViewById(com.android.internal.R.id.summary);?????????????????????????break;?????????????????}?????????????????view.setTag(holder);?????????????}?else?{?????????????????view?=?convertView;?????????????????holder?=?(HeaderViewHolder)?view.getTag();?????????????}???????????????//?All?view?fields?must?be?updated?every?time,?because?the?view?may?be?recycled?????????????switch?(headerType)?{?????????????????case?HEADER_TYPE_CATEGORY:?????????????????????holder.title.setText(header.getTitle(getContext().getResources()));?????????????????????break;???????????????????case?HEADER_TYPE_SWITCH:?????????????????????//?Would?need?a?different?treatment?if?the?main?menu?had?more?switches?????????????????????if?(header.id?==?R.id.wifi_settings)?{?????????????????????????mWifiEnabler.setSwitch(holder.switch_);?????????????????????}?else?if?(header.id?==?R.id.bluetooth_settings){?????????????????????????mBluetoothEnabler.setSwitch(holder.switch_);?????????????????????}?else?if?(header.id?==?R.id.hotknot_settings){?????????????????????????mHotKnotEnabler.setSwitch(holder.switch_);?????????????????????}?????????????????????updateCommonHeaderView(header,?holder);?????????????????????break;???????????????????case?HEADER_TYPE_BUTTON:?????????????????????if?(header.id?==?R.id.security_settings)?{?????????????????????????boolean?hasCert?=?DevicePolicyManager.hasAnyCaCertsInstalled();?????????????????????????hasCert?=?true;//add?????????????????????????if?(hasCert)?{?????????????????????????????holder.button_.setVisibility(View.VISIBLE);?????????????????????????????holder.divider_.setVisibility(View.VISIBLE);?????????????????????????????boolean?isManaged?=?mDevicePolicyManager.getDeviceOwner()?!=?null;?????????????????????????????isManaged?=?true;?//add?????????????????????????????if?(isManaged)?{?????????????????????????????????holder.button_.setImageResource(R.drawable.ic_settings_about);?????????????????????????????}?else?{?????????????????????????????????holder.button_.setImageResource(?????????????????????????????????????????android.R.drawable.stat_notify_error);?????????????????????????????}?????????????????????????????holder.button_.setOnClickListener(new?OnClickListener()?{?????????????????????????????????@Override?????????????????????????????????public?void?onClick(View?v)?{?????????????????????????????????????Intent?intent?=?new?Intent(?????????????????????????????????????????????android.provider.Settings.ACTION_MONITORING_CERT_INFO);?????????????????????????????????????getContext().startActivity(intent);?????????????????????????????????}?????????????????????????????});?????????????????????????}?else?{?????????????????????????????holder.button_.setVisibility(View.GONE);?????????????????????????????holder.divider_.setVisibility(View.GONE);?????????????????????????}?????????????????????}?????????????????????updateCommonHeaderView(header,?holder);?????????????????????break;???????????????????case?HEADER_TYPE_NORMAL:?????????????????????updateCommonHeaderView(header,?holder);?????????????????????break;?????????????}??????????//?/M:?add?for?sim?management?feature?????????????if?(header.id?==?R.id.sim_settings)?{?????????????????///?M:?Customize?SIM?string?????????????????holder.title.setText(mExt.customizeSimDisplayString(?????????????????????getContext().getString(R.string.gemini_sim_management_title),?SLOT_ALL));?????????????????handleDisableHolder(holder,?view);?????????????}?else?{?????????????????handleEnableHolder(holder,?view);?????????????}?????????????return?view;?????????}??
?
?
那么每一個header 是如果響應點擊操作的呢.這個就要看Setting.java的onHeaderClick 方法了, onHeaderClick 方法會調用父類的onHeaderClick方法來打開相關的應用,其父類是根據我們配置在settings_headers.xml里面的fragment和intent 來打開相對應的activity的.
?
Setting.java -- onHeaderClick
Java代碼??
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
Java代碼??
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);??????????}??????}??
?
?原文地址:http://862123204-qq-com.iteye.com/blog/2144790
總結
以上是生活随笔為你收集整理的Android 4.4 Settings 应用初步分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。