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. Codeforces 1194D. 1-2-K Game

    传送门 先考虑只能走 $1,2$ 步的情况,设 $p[i]$ 表示当 $n=i$ 时先手是否必胜 自己手玩一下发现 $p$ 就是 $011011011...011$ 这样循环(下标从 $0$ 开始,其 ...

  2. JDK SPI

    最近学习了JDK SPI   JDK SPI是什么 最近工作中听几个同事说了好几次SPI这个名词,虽然和我没关系,但是心里默默想还是学习一下,不然下次和我说到SPI,连是什么都不知道那就尴尬了. 所以 ...

  3. volatile关键字和transient关键字

    Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量 1.volatile 关键字-----针对变量的可变性 专业解释:volatile关键字是个类型修饰符用它声明的类型变 ...

  4. 精通shell编程--最后的总结

    不得不说shell语法是丑陋的,操作是简单高效的,最后一次学习总结shell shell总结 字符串删除与替换等常见操作 ## 字符串长度 a=1234 echo "${#a}" ...

  5. freemarker的replace的使用

    1.replace替换: <#assign name="sdfsfdsa\ndfsafs\n"> 例子:${name?replace("\n",&q ...

  6. Js实现图片点击切换与轮播

    Js实现图片点击切换与轮播 图片点击切换 <!DOCTYPE html> <html> <head> <meta charset="UTF-8&qu ...

  7. Java LinkedHashMap学习

    以前一直使用HashMap,今天学习一下LinkedHashMap JavaDoc 注解: Hash table and linked list implementation of the Map i ...

  8. IT技术网站博客推荐

    CSDN 全球最大中文IT社区,为IT专业技术人员提供最全面的信息传播和服务平台. 51CTO 技术成就梦想 - 中国领先的IT技术网站 itEye Java编程 Spring框架 Ajax技术 ag ...

  9. django用户投票系统详解

    投票系统之详解 1.创建项目(mysite)与应用(polls) django-admin.py startproject mysite python manage.py startapp polls ...

  10. 牛客练习赛46 C 华华跟奕奕玩游戏 (期望,概率)(详解)

    链接:https://ac.nowcoder.com/acm/contest/894/C 来源:牛客网 华华跟奕奕玩游戏 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K ...