2.1 Activity::setContentView()
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
1
2
3
4
5
6
7
2.2 mWindow的初始化是在Activity的attach方法中执行的。了解过Activity启动流程,我们知道:attach方法是在Activity启动流程中,ActivityThread::performLaunchActivity()方法中被调用的,是在Activity被创建后,完成初始化操作的。
//android.app.Activity#attach()
final void attach(Context context, ActivityThread aThread, ... Window window ...) {
...
//这里进行mWindow的初始化,可以看到Activity中的Window实现类是PhoneWindow,
//目前为止,PhoneWindow也是Window的唯一实现类
mWindow = new PhoneWindow(this, window, activityConfigCallback);
//这里是给Window设置了WindowManager,WindowManager是通过IPC获取的系统服务,
//WindowManager只是一个接口类型,具体实现是WindowManagerImpl类,
//当然WindowManagerImpl又将实际的逻辑实现交给了WindowManagerGlobal类
mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
//Activity持有的WindowManager也是从Window中拿过来的
mWindowManager = mWindow.getWindowManager();
....
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2.3 继续看PhoneWindow的setContentView()实现代码
@Override
public void setContentView(int layoutResID) {
//mContentParent其实就是android.R.id.content布局对应的实际展示的内容
if (mContentParent == null) {
//这个方法时构造一个顶层的DecorView对象,其实是直接通过new DecorView产生的实例对象,并赋值给mDecor变量
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
//第二次调用setContentView()方法时走这里,会先remove掉所有的子View再通过inflate进行加载布局
mContentParent.removeAllViews();
}

if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
//这个变量,会在requestFeature()方法调用时判断时机是否正确,
//如果实在setContentView之后调用的,会抛出"requestFeature() must be called before adding content"的异常
mContentParentExplicitlySet = true;
}
//installDecorView():构造Activity视图框架的根视图,并通过LayoutInflater加载mContentParent,
//我们一般操作的setContentView其实就是将布局展示到了mContentParent中
private void installDecor() {
...
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//DecorView已经构造好了,可以从DecorView中通过findViewById的方式实例化mContentParent对象了
mContentParent = generateLayout(mDecor);
}
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2.4 generateLayout(mDecor)也是获取mContentParent对象的关键方法
protected ViewGroup generateLayout(DecorView decor) {
...
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
setCloseOnSwipeEnabled(true);
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
layoutResource = R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
layoutResource = R.layout.screen_simple;
}
....
//mDecorView虽然已经初始化了,但是他的布局还未加载,通过上面对features变量值的一堆if-else判断,
//获取到对应的feature值的布局文件,再通过inflater对象加载布局
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//这里获取的就是mContentParent对象,findViewById是View的方法,这里是间接调用了DecorView的findViewById方法,
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
2.5 查找ID_ANDROID_CONTENT变量,可以看到:其值是android.R.id.content
/**
* The ID that the main layout in the XML layout file should have.
*/
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
1
2
3
4
2.6 另外: DecorView加载布局文件资源的方法是:onResourcesLoaded()
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
...
//这里inflate方法的root直接传null,的确这已经是跟布局了,肯定是没有父View可以传了
final View root = inflater.inflate(layoutResource, null);
...
}

从setContentView()源码看起的更多相关文章

  1. 从源码看Azkaban作业流下发过程

    上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...

  2. 解密随机数生成器(二)——从java源码看线性同余算法

    Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术 ...

  3. 从源码看Android中sqlite是怎么通过cursorwindow读DB的

    更多内容在这里查看 https://ahangchen.gitbooks.io/windy-afternoon/content/ 执行query 执行SQLiteDatabase类中query系列函数 ...

  4. 从源码看Android中sqlite是怎么读DB的(转)

    执行query 执行SQLiteDatabase类中query系列函数时,只会构造查询信息,不会执行查询. (query的源码追踪路径) 执行move(里面的fillwindow是真正打开文件句柄并分 ...

  5. 从Chrome源码看浏览器的事件机制

    .aligncenter { clear: both; display: block; margin-left: auto; margin-right: auto } .crayon-line spa ...

  6. 从Chrome源码看JS Array的实现

    .aligncenter { clear: both; display: block; margin-left: auto; margin-right: auto } .crayon-line spa ...

  7. 从源码看JDK提供的线程池(ThreadPoolExecutor)

    一丶什么是线程池 (1)博主在听到线程池三个字的时候第一个想法就是数据库连接池,回忆一下,我们在学JavaWeb的时候怎么理解数据库连接池的,数据库创建连接和关闭连接是一个比较耗费资源的事情,对于那些 ...

  8. 从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

    使用微信小程序开发已经很长时间了,对小程序开发已经相当熟练了:但是作为一名对技术有追求的前端开发,仅仅熟练掌握小程序的开发感觉还是不够的,我们应该更进一步的去理解其背后实现的原理以及对应的考量,这可能 ...

  9. 从微信小程序开发者工具源码看实现原理(四)- - 自适应布局

    从前面从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计可以知道,小程序大部分是通过web技术进行渲染的,也就是最终通过浏览器的dom tree + cssom来生成渲染树:既然最终是通 ...

随机推荐

  1. Ubuntu分区挂载

    创建主分区: 25G    主分区    空间起始位置    Ext4日志文件系统    / (ps:安装主要放这了,原因不明) 创建swap分区: 8192MB    逻辑分区        空间起 ...

  2. kinit: Bad encryption type while getting initial credentials

    描述:RHEL 6.x主机执行kinit -kt命令报如下错误 [heboan@localhost~]$ kinit -kt heboan.keytab heboan kinit: Bad encry ...

  3. ES6 模块的加载实现 import和export

    ES6的Class只是面向对象编程的语法糖,升级了ES5的构造函数的原型链继承的写法,并没有解决模块化问题.Module功能就是为了解决这个问题而提出的. 历史上,JavaScript一直没有模块(m ...

  4. microsoft office powerpoibt automation 二次开发

    背景 首先office的产品powerpoint是支持二次开发的,这里的二次开发并不是指在powerpoint产品中嵌入一些自己的控件,而是一些简单的automation的控制(进入放映状态,上一页, ...

  5. 17种常用的JS正则表达式 非负浮点数 非负正数

    <input type='text' id='SYS_PAGE_JumpPage' name='SYS_PAGE_JumpPage' size='3' maxlength='5' onkeyup ...

  6. (持续更新中~~~)kafka--消息引擎与分布式流处理平台

    kafka概述 kafka是一个分布式的基于发布/订阅模式的消息队列(message queue),一般更愿意称kafka是一款开源的消息引擎系统,只不过消息队列会耳熟一些.kafka主要应用于大数据 ...

  7. 运维都该会的Socket知识!

    本篇博客转自赵班长 所有运维都会的Socket知识!!! 原创: 赵班长 新运维社区 什么是Socket? 大家都用电脑上网,当我们访问运维社区https://www.unixhot.com的时候,我 ...

  8. insightface作者提供数据训练解读

    1.下载源码: 开源代码地址:https://github.com/deepinsight/insightface 2.查看作者项目训练要求 (1)训练数据 训练数据使用作者提供并制作好的数据,如下图 ...

  9. A Neural Probabilistic Language Model (2003)论文要点

    论文链接:http://www.jmlr.org/papers/volume3/bengio03a/bengio03a.pdf 解决n-gram语言模型(比如tri-gram以上)的组合爆炸问题,引入 ...

  10. 介绍知道的http返回的状态码

    100    Continue    继续.客户端应继续其请求 101    Switching Protocols    切换协议.服务器根据客户端的请求切换协议.只能切换到更高级的协议,例如,切换 ...