Android 4.4 Settings 应用初步分析

一次偶然要在设置里面增加一个菜单,需要修改到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代码   收藏代码
  1. <!-- WIRELESS and NETWORKS  分类-->  
  2.     <header android:id="@+id/wireless_section"  
  3.         android:title="@string/header_category_wireless_networks" />  
  4.   
  5.     <!-- Sim management 普通项-->  
  6.     <header  
  7.         android:id="@+id/sim_settings"  
  8.         android:icon="@drawable/ic_settings_dualsim"  
  9.         android:fragment="com.mediatek.gemini.SimManagement"  
  10.         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代码   收藏代码
  1. /** 
  2.      * Populate the activity with the top-level headers. 
  3.      */  
  4.     @Override  
  5.     public void onBuildHeaders(List<Header> headers) {  
  6.         if (!onIsHidingHeaders()) {  
  7.             PDebug.Start("loadHeadersFromResource");  
  8.             loadHeadersFromResource(R.xml.settings_headers, headers);  
  9.             PDebug.End("loadHeadersFromResource");  
  10.             updateHeaderList(headers);  
  11.         }  
  12.     }  

 

 

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代码   收藏代码
  1. static final int HEADER_TYPE_CATEGORY = 0;//用来分类的  
  2. static final int HEADER_TYPE_NORMAL = 1;//常规项  
  3. static final int HEADER_TYPE_SWITCH = 2;//开关项  
  4. static final int HEADER_TYPE_BUTTON = 3;//按钮项  

 

前3种应该都见过,为了让大家看到第4项,我把稍微修改了一下我的HeaderAdapter源码(见getview方法的中的有//add的部分),也就是上面图2中的security 选项.

HeaderAdapter 的getHeaderType 方法决定了配置在settings_headers.xml 里面的header的类型.

HeaderAdapter 的getView 方法根据header的类型 来加载对应的布局文件.

Java代码   收藏代码
  1. static int getHeaderType(Header header) {  
  2.             if (header.fragment == null && header.intent == null) {  
  3.                 return HEADER_TYPE_CATEGORY;  
  4.             } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings  
  5.                      || header.id == R.id.hotknot_settings) {  
  6.                 return HEADER_TYPE_SWITCH;  
  7.             } else if (header.id == R.id.security_settings) {  
  8.                 return HEADER_TYPE_BUTTON;  
  9.             } else {  
  10.                 return HEADER_TYPE_NORMAL;  
  11.             }  
  12.         }  

 

但要注意的是在getView方法里面,当发现一个header 的类型是button的时候也会给header 的button增加一个onclick事件的,这个事件和header本事的onHeaderClick 是没有冲突的,因为2者不受同一个控件.

Java代码   收藏代码
  1. @Override  
  2.        public View getView(int position, View convertView, ViewGroup parent) {  
  3.            HeaderViewHolder holder;  
  4.            Header header = getItem(position);  
  5.            int headerType = getHeaderType(header);  
  6.            Log.d("zhangle","getHeaderType" + header.title  + " headerType=" + headerType);  
  7.            View view = null;  
  8.   
  9.            if (convertView == null) {  
  10.                holder = new HeaderViewHolder();  
  11.                switch (headerType) {  
  12.                    case HEADER_TYPE_CATEGORY:  
  13.                        view = new TextView(getContext(), null,  
  14.                                android.R.attr.listSeparatorTextViewStyle);  
  15.                        holder.title = (TextView) view;  
  16.                        break;  
  17.   
  18.                    case HEADER_TYPE_SWITCH:  
  19.                        view = mInflater.inflate(R.layout.preference_header_switch_item, parent,  
  20.                                false);  
  21.                        holder.icon = (ImageView) view.findViewById(R.id.icon);  
  22.                        holder.title = (TextView)  
  23.                                view.findViewById(com.android.internal.R.id.title);  
  24.                        holder.summary = (TextView)  
  25.                                view.findViewById(com.android.internal.R.id.summary);  
  26.                        holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);  
  27.                        break;  
  28.   
  29.                    case HEADER_TYPE_BUTTON:  
  30.                        view = mInflater.inflate(R.layout.preference_header_button_item, parent,  
  31.                                false);  
  32.                        holder.icon = (ImageView) view.findViewById(R.id.icon);  
  33.                        holder.title = (TextView)  
  34.                                view.findViewById(com.android.internal.R.id.title);  
  35.                        holder.summary = (TextView)  
  36.                                view.findViewById(com.android.internal.R.id.summary);  
  37.                        holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);  
  38.                        holder.divider_ = view.findViewById(R.id.divider);  
  39.                        break;  
  40.   
  41.                    case HEADER_TYPE_NORMAL:  
  42.                        view = mInflater.inflate(  
  43.                                R.layout.preference_header_item, parent,  
  44.                                false);  
  45.                        holder.icon = (ImageView) view.findViewById(R.id.icon);  
  46.                        holder.title = (TextView)  
  47.                                view.findViewById(com.android.internal.R.id.title);  
  48.                        holder.summary = (TextView)  
  49.                                view.findViewById(com.android.internal.R.id.summary);  
  50.                        break;  
  51.                }  
  52.                view.setTag(holder);  
  53.            } else {  
  54.                view = convertView;  
  55.                holder = (HeaderViewHolder) view.getTag();  
  56.            }  
  57.   
  58.            // All view fields must be updated every time, because the view may be recycled  
  59.            switch (headerType) {  
  60.                case HEADER_TYPE_CATEGORY:  
  61.                    holder.title.setText(header.getTitle(getContext().getResources()));  
  62.                    break;  
  63.   
  64.                case HEADER_TYPE_SWITCH:  
  65.                    // Would need a different treatment if the main menu had more switches  
  66.                    if (header.id == R.id.wifi_settings) {  
  67.                        mWifiEnabler.setSwitch(holder.switch_);  
  68.                    } else if (header.id == R.id.bluetooth_settings){  
  69.                        mBluetoothEnabler.setSwitch(holder.switch_);  
  70.                    } else if (header.id == R.id.hotknot_settings){  
  71.                        mHotKnotEnabler.setSwitch(holder.switch_);  
  72.                    }  
  73.                    updateCommonHeaderView(header, holder);  
  74.                    break;  
  75.   
  76.                case HEADER_TYPE_BUTTON:  
  77.                    if (header.id == R.id.security_settings) {  
  78.                        boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();  
  79.                        hasCert = true;//add  
  80.                        if (hasCert) {  
  81.                            holder.button_.setVisibility(View.VISIBLE);  
  82.                            holder.divider_.setVisibility(View.VISIBLE);  
  83.                            boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;  
  84.                            isManaged = true//add  
  85.                            if (isManaged) {  
  86.                                holder.button_.setImageResource(R.drawable.ic_settings_about);  
  87.                            } else {  
  88.                                holder.button_.setImageResource(  
  89.                                        android.R.drawable.stat_notify_error);  
  90.                            }  
  91.                            holder.button_.setOnClickListener(new OnClickListener() {  
  92.                                @Override  
  93.                                public void onClick(View v) {  
  94.                                    Intent intent = new Intent(  
  95.                                            android.provider.Settings.ACTION_MONITORING_CERT_INFO);  
  96.                                    getContext().startActivity(intent);  
  97.                                }  
  98.                            });  
  99.                        } else {  
  100.                            holder.button_.setVisibility(View.GONE);  
  101.                            holder.divider_.setVisibility(View.GONE);  
  102.                        }  
  103.                    }  
  104.                    updateCommonHeaderView(header, holder);  
  105.                    break;  
  106.   
  107.                case HEADER_TYPE_NORMAL:  
  108.                    updateCommonHeaderView(header, holder);  
  109.                    break;  
  110.            }  
  111.         // /M: add for sim management feature  
  112.            if (header.id == R.id.sim_settings) {  
  113.                /// M: Customize SIM string  
  114.                holder.title.setText(mExt.customizeSimDisplayString(  
  115.                    getContext().getString(R.string.gemini_sim_management_title), SLOT_ALL));  
  116.                handleDisableHolder(holder, view);  
  117.            } else {  
  118.                handleEnableHolder(holder, view);  
  119.            }  
  120.            return view;  
  121.        }  

 

 

那么每一个header 是如果响应点击操作的呢.这个就要看Setting.java的onHeaderClick 方法了, onHeaderClick 方法会调用父类的onHeaderClick方法来打开相关的应用,其父类是根据我们配置在settings_headers.xml里面的fragment和intent 来打开相对应的activity的.

 

Setting.java -- onHeaderClick

Java代码   收藏代码
  1. public void onHeaderClick(Header header, int position) {  
  2.         boolean revert = false;  
  3.         if (header.id == R.id.account_add) {  
  4.             revert = true;  
  5.         }  
  6.   
  7.         super.onHeaderClick(header, position);  
  8.   
  9.         if (revert && mLastHeader != null) {  
  10.             highlightHeader((int) mLastHeader.id);  
  11.         } else {  
  12.             mLastHeader = header;  
  13.         }  
  14.     }  

 

PreferenceActivity -- onHeaderClick

Java代码   收藏代码
  1. public void onHeaderClick(Header header, int position) {  
  2.         if (header.fragment != null) {  
  3.             if (mSinglePane) {  
  4.                 Log.d(TAG, "onHeaderClick, single pane and startWithFragment.");  
  5.                 int titleRes = header.breadCrumbTitleRes;  
  6.                 int shortTitleRes = header.breadCrumbShortTitleRes;  
  7.                 if (titleRes == 0) {  
  8.                     titleRes = header.titleRes;  
  9.                     shortTitleRes = 0;  
  10.                 }  
  11.                 startWithFragment(header.fragment, header.fragmentArguments, null0,  
  12.                         titleRes, shortTitleRes);  
  13.             } else {  
  14.                 Log.d(TAG, "onHeaderClick, multiple pane and switchToHeader.");  
  15.                 switchToHeader(header);  
  16.             }  
  17.         } else if (header.intent != null) {  
  18.             Log.d(TAG, "onHeaderClick, start activity with header intent.");  
  19.             startActivity(header.intent);  
  20.         }  
  21.     }  

 

 原文地址:http://862123204-qq-com.iteye.com/blog/2144790

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值