2017/9/8 17:17:03
 

前言

    最近接到个需要优化Android原生系统设置APK的任务。这个任务里面有一个更换应用背景图片的需求。我手里的这个设备是一个平板设备,使用了一下这个原生设置APK,感觉它有点像是一个主Activity,通过更换Fragment的方式来切换不同的展示内容。这样一来就好办了,想着直接找到这个Activity,看看它是 set 了哪一个 layout 进去,然后再直接在这个 layout 中添加个背景图片就好了。但后来跟踪了一下源码,发现并没有这么简单。这个主Activity是继承自Android打包好的 PreferenceActivity 来实现的,而设置布局的工作,已经由这个父Activity完成了(如下图所示)。完全没有子Activity什么事,并且PreferenceActivity还没有暴露任何接口能让子类取得布局。而且像这种设置方式,想反射都不好反射。
./frameworks/base/core/java/android/preference/PreferenceActivity.java
 
    那这样可如何是好呢?如果能有一个 getContentView() 方法就好了。既然Android官方不提供,那我们干脆跟踪跟踪源码,看看能不能自己造一个出来。
 

开发环境

    操作系统:Android4.4.2
    硬件设备:智能音箱中的平板设备。
    编译需求:有完整源代码,能够正常编译大包。
 
 

追本溯源-跟踪源代码

    首先来看看Activity.java中的 setContentView() 是如何处理的。
./frameworks/base/core/java/android/app/Activity.java
 

原来与 Window 有关啊。再看看 getWindow() 中是如何提供 Window 对象的。

到这里,我们就知道了,Activity中使用的 Window 就是 PhoneWindow 类的对象了。那么,我们直接去 PhoneWindow 类中看看它的 setContentView() 作了什么操作。
 
./frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
 

由上图所示代码第290行,我们知道了原来 set 进去的 layout 就是被加载到了这个 mContentParent 容器中去了啊。这个 mContentParent 是一个 ViewGroup 类的对象。那这个 mContentParent 又是怎么来的呢?
注意到上图第285行的条件判断语句里,似乎这个 mContentParent 对象还与 installDecor() 方法有关呢!去看看。
 

看来刚才猜想的没错,这个 mContentParent 确实和这个 Decor 有着很密切的关系。先去 generateDecor() 方法里看看这个 mDecor 是个什么来头。

 简单粗暴,我喜欢!!!DecorView是一个定义在 PhoneWindow 内部的内部类,它是 FrameLayout 的子类,如下图所示。

 
然后我们再去看看 mContentParent 是如何由 mDecor 生成的。追踪 generateLayout() 方法。
generateLayout() 方法代码量较大,我们不需要看懂每一行代码的含义,只看我们需要的就好。
protected ViewGroup generateLayout(DecorView decor) {
// 为后续的加载作前期准备工作,读取属性值,选择布局文件等。
// ...
mDecor.startChanging(); View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);// ID_ANDROID_CONTENT = com.android.internal.R.id.content;
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
} if (getContainer() == null) {
Drawable drawable = mBackgroundDrawable;
if (mBackgroundResource != 0) {
drawable = getContext().getResources().getDrawable(mBackgroundResource);
}
mDecor.setWindowBackground(drawable);
drawable = null;
if (mFrameResource != 0) {
drawable = getContext().getResources().getDrawable(mFrameResource);
}
mDecor.setWindowFrame(drawable);
} mDecor.finishChanging(); return contentParent;
}
 
由上述代码第7行可知,mDecor在这里添加了一个View,准确说,它添加的肯定是一个 ViewGroup 类对象。这次添加也是 mDecor 首次添加,即在 mDecor 的 child 中,它是第0个。
然后第9行的 ViewGroup contentParent 就是最终要返回的容器对象。这行代码后面的 findViewById() 方法是定义在 Window.java 中的方法。它其实就是通过 mDecor 来根据 ID 查找 View 。
./frameworks/base/core/java/android/view/Window.java
 

 
到这里,整个加载布局的流程就很清楚了。我们把它总结一下。

 
那么,借此设置流程图,创造 getContentView() 方法的步骤也清晰了。如下图所示:

这里有一个很重要的、也是关键的一点,就是Activity提供了 getWindow() 方法用于取得 Window 对象,且这个 Window 对象又提供了取得 mDecorView 对象的接口。
 
 

代码实操

更改Android原生系统设置APK中的背景图片。
./packages/apps/Settings/src/.../Settings.java
 

 
至此,我们不仅完成了更换不是由自己设置布局的Activity的背景图片,还了解到了系统设置布局的流程的知识。
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

 
 
 
 

在 Activity 中实现 getContentView 操作的更多相关文章

  1. Android 实现在Activity中操作刷新另外一个Activity数据列表

    做android项目中遇到这样一个问题:有两个acticity,一个显示好友列表,另外一个显示会话列表,现在问题是在会话界面增加一个添加好友功能,添加好友后要求实时的刷新好友列表. 想了想,找了两种方 ...

  2. 我的Android六章:Android中SQLite数据库操作

    今天学习的内容是Android中的SQLite数据库操作,在讲解这个内容之前小编在前面有一篇博客也是讲解了SQLite数据库的操作,而那篇博客的讲解是讲述了 如何在Window中通过DOM来操作数据库 ...

  3. android开发之在activity中控制另一个activity的UI更新

    转自:http://blog.csdn.net/jason0539/article/details/18075293 第一种方法: 遇到一个问题,需要在一个activity中控制另一个acitivit ...

  4. Android 管理Activity中的fragments

    为了管理Activity中的fragments,需要使用FragmentManager,为了得到它,需要调用Activity中的getFragmentManager()方法,接下来详细介绍,感兴趣的朋 ...

  5. Activity中的四种启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  6. android中的数据库操作(转)

    android中的数据库操作 android中的应用开发很难避免不去使用数据库,这次就和大家聊聊android中的数据库操作. 一.android内的数据库的基础知识介绍 1.用了什么数据库   an ...

  7. android中的文件操作详解以及内部存储和外部存储(转载)

    原文链接:http://m.blog.csdn.net/article/details?id=17725989 摘要 其实安卓文件的操作和java在pc环境下的操作并无二致,之所以需要单独讲解是因为安 ...

  8. 在Activity中响应ListView内部按钮的点击事件的两种方法!!!

    在Activity中响应ListView内部按钮的点击事件的两种方法 转载:http://www.cnblogs.com/ivan-xu/p/4124967.html 最近交流群里面有人问到一个问题: ...

  9. Fragment在Activity中的应用 (转载)

    原文链接 http://www.cnblogs.com/nanxin/archive/2013/01/24/2875341.html 在本小节中介绍在Activity中创建Fragment. 官网有很 ...

随机推荐

  1. 第一行代码:以太坊(2)-使用Solidity语言开发和测试智能合约

    智能合约是以太坊的核心之一,用户可以利用智能合约实现更灵活的代币以及其他DApp.不过在深入讲解如何开发智能合约之前,需要先介绍一下以太坊中用于开发智能合约的Solidity语言,以及相关的开发和测试 ...

  2. 【C#复习总结】细说表达式树

    1 前言 系类1:细说委托 系类2:细说匿名方法 系列3:细说Lambda表达式 系列4:细说泛型委托 系列5:细说表达式树 系列6:细说事件 涛声依旧,再续前言,接着用大佬的文章作为开头. 表达式树 ...

  3. 【Python入门只需20分钟】从安装到数据抓取、存储原来这么简单

    基于大众对Python的大肆吹捧和赞赏,作为一名Java从业人员,我本着批判与好奇的心态买了本python方面的书<毫无障碍学Python>.仅仅看了书前面一小部分的我......决定做一 ...

  4. LINQ基本概念及误区

    LINQ基本概念: LINQ全名Language Integrated Query(语言集成查询),它允许我们通过C#(或VB)语言,以操作内存数据的方式,查询数据库. LINQ的由来: 传统上,对数 ...

  5. 异步时代-java的协程路在何方

    面试官:你知道协程吗? 你:订机票的那个吗,我常用. 面试官:行,你先回去吧,到时候电话联系 ........ 很尴尬,但是事实是,很大一部分的程序员不知道协程是啥玩意,更大一部分的程序员,项目中没用 ...

  6. matplot绘图基本使用

    先看一个最简单的例子 import matplotlib.pyplot as plt plt.figure() plt.subplot(211) plt.plot([1,2,3], color=''r ...

  7. Django的model form组件

    前言 首先对于form组件通过全面的博客介绍,对于form我们应该知道了它的大致用法,这里我们需要明确的一点是,我们定义的form与model其实没有什么关系,只是在逻辑上定义form的时候字段名期的 ...

  8. 怎么用npm发布一个包,详细教程

    我们已经实现了路由的自动化构建,但是我们可以看到,一大串代码怼在里面.当然你也可以说,把它封装在一个JS文件里面,然后使用require('./autoRoute.js')给引入进来,那也行.但是,为 ...

  9. 多项式求值 n维多项式 Horner解法

    #include<iostream> using namespace std; template<class T> T ploy(T *coeff,int n,const T& ...

  10. Unique Snowflakes UVA - 11572 (离散化+尺取法)

    Emily the entrepreneur has a cool business idea: packaging and selling snowflakes. She has devised a ...