`

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.

<!-- 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源码(见getview方法的中的有//add的部分),也就是上面图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方法里面,当发现一个header 的类型是button的时候也会给header 的button增加一个onclick事件的,这个事件和header本事的onHeaderClick 是没有冲突的,因为2者不受同一个控件.

 @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

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);
        }
    }

 

 

  • 大小: 112.8 KB
  • 大小: 118.3 KB
0
0
分享到:
评论

相关推荐

    Android4.4 settings源码

    Android 4.4 的 Settings 应用是操作系统中至关重要的组成部分,它负责提供用户界面来配置设备的各种系统设置。Settings 源码分析可以帮助我们深入理解 Android 系统的工作原理,特别是用户界面与系统服务之间的交互...

    android 4.4 Settings

    在Android 4.4系统中,Settings应用是用户与设备设置进行交互的主要界面,它包含了各种设备配置选项,如网络设置、显示设置、声音、安全等。深入理解Settings的源码对于Android开发者来说至关重要,因为它可以帮助...

    Vue中android4.4不兼容问题的解决方法

    在使用Vue.js开发的Web应用中,可能会遇到与Android 4.4版本不兼容的问题。考虑到Android 4.4在市场份额中仍占有一定比例,特别是在一些较为老旧的设备或新兴市场中,解决这些兼容性问题是提升用户体验的重要一环。 ...

    Android4.4的source包

    Android 4.4源码是开源的,允许开发者深入研究系统内部的工作机制,这对于定制ROM、性能优化以及系统级应用开发具有重要意义。解压后的源码位于`XXXX\sdk\platforms\android-19`路径下,这包含了Android系统的各个...

    适用于Android4.4版vlc源码+so库

    总的来说,这个资源对于那些需要在Android 4.4系统上部署或改进VLC应用的开发者来说非常有价值。通过获取和研究源码,开发者不仅可以修复已知问题,还能为旧设备提供持续的软件支持,增强用户体验。同时,这也为学习...

    android4.4源码 android4.4源码包 android4.4 source jar

    Android Studio在4.4时期成为官方开发工具,提供了强大的调试功能、代码分析和性能优化工具。源码关联功能使开发者可以直接查看源码,快速定位问题,提高开发效率。 九、服务框架 Android 4.4的服务框架支持云同步...

    Android 4.4 SDK 文档

    Android 4.4 SDK(软件开发工具包)是Android开发者为构建、测试和发布针对Android 4.4 KitKat版本应用的重要工具集。这个版本的SDK包含了一系列的文档、库、示例代码、调试工具和其他资源,使得开发者能够充分利用...

    Android 4.4 设置壁纸流程

    在Android 4.4系统中,用户可以根据个人喜好设置静态壁纸或动态壁纸,为设备增添个性化的视觉体验。本文将详细介绍这两种壁纸的设置流程,并通过思维导图的方式帮助理解每一步的操作步骤。 首先,我们来看静态壁纸...

    Android 4.4 SDK Reference 官方帮助文档

    3. **开发者工具**: Android 4.4 SDK包括了集成开发环境(IDE)Android Studio,以及各种工具如ADB(Android Debug Bridge)、DDMS(Device Manager and Debugger)和布局设计器等,帮助开发者调试、测试和优化应用。...

    Android4.4系统应用——FactoryKit

    **FactoryKit在Android 4.4系统中的应用** FactoryKit是Android系统中一个重要的工具,尤其在设备制造商和开发者中广泛使用。它主要用于设备的生产和测试阶段,提供了一种工程模式来对Android设备进行深入的诊断和...

    Android4.4Contacts源码

    在Android 4.4系统中,Contacts应用是用户管理联系人的重要组成部分。它不仅负责显示、编辑和组织联系人的信息,还与其他系统服务如Google账户同步、来电显示等功能紧密协作。这里我们将深入探讨Android 4.4 ...

    谷歌Chrome浏览器x86版APK低版本Android4.4可用浏览器版本是72.0

    这款“谷歌Chrome浏览器x86版APK低版本Android4.4可用浏览器版本是72.0”是专为使用x86架构设备的用户设计的,如某些平板电脑和安卓模拟器。对于那些在Android 4.4(KitKat)系统上运行的设备,这是一个理想的解决...

    android4.4的core源码

    1. **应用程序框架**:Android 4.4的App Framework提供了各种服务和接口,如ActivityManager、ContentProvider、Intent等,这些都是构建Android应用的基础。通过查看源码,我们可以了解这些组件的工作原理,以及如何...

    android 4.4 源码 eclipse 浏览

    本篇将详细探讨如何使用Eclipse来浏览和分析Android 4.4的源码。 首先,要准备Eclipse IDE,这是Android开发者常用的集成开发环境。为了浏览源码,我们需要安装ADT(Android Developer Tools)插件,它包含了源码...

    静默安装apk android4.4

    在Android 4.4(KitKat)版本中,这个功能主要应用于企业级设备管理和批量部署应用的场景。下面我们将详细探讨如何在Android 4.4上实现APK的静默安装以及相关的知识点。 1. **权限要求**: 在Android 4.4中,静默...

    Android4.4+短信拦截删除

    在Android 4.4(KitKat)及更高版本中,为了增强用户体验和安全性,系统提供了更高级别的API来处理短信,包括拦截和删除短信。本文将深入探讨Android 4.4+短信拦截删除的相关知识点。 首先,我们要了解的是`...

    Android4.4W(API20)源码

    通过分析和学习Android 4.4W源码,开发者不仅可以提升应用性能,还能为可穿戴设备创造独特的用户体验。不过,源码学习是一项复杂任务,需要扎实的编程基础和耐心,同时也为进阶Android开发提供了宝贵资源。

    android4.4SDK源码包

    通过学习和分析Android 4.4 SDK源码,开发者可以提高自己的编程技巧,更好地理解和定制Android系统,为创建更高效、更稳定的应用程序打下坚实的基础。同时,对于希望成为系统级开发者或从事ROM定制的人来说,源码...

    android4.4源码下载

    Android 4.4源码中包含了系统服务、框架、库和各种应用程序的实现,比如ActivityManagerService负责管理应用的生命周期,ContentProvider实现了数据共享,以及WebView的实现等。深入研究这些代码可以帮助你理解...

    android 4.4 系统源码

    Android 4.4系统源码是开发者深入了解Android操作系统工作原理的重要资源,对于系统级开发者、应用开发者以及希望优化性能或定制系统的爱好者来说,都是不可或缺的学习资料。这份源码包含了从底层驱动到上层应用程序...

Global site tag (gtag.js) - Google Analytics