版本:27.1.1
观看目录:
- Activity:启动流程
- Activity:xml如何通过加载到UI界面
结合 Activity:启动流程
的流程图:
Activity:启动流程
如果对Activity的启动流程不熟悉的请移步:Activity:启动流程
下图是从
Activity启动
到
XML如何加载到UI界面
的:
图有点大,可以点击图片放大查看:
建议跟着源码过一遍流程图熟悉下,在看更容易理解!
本文章分析流程图
截选自上图后半部分。
本文分析分三个方面来说:
- setContentView为XML加载到UI做了哪些准备工作?
- setContentView之后Activity如何开始运转工作的?
- 从开始运转工作到测量绘制布局做了哪些工作?
setContentView
源码:PhoneWindow中的setContentView
// 只保留两个核心方法
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
// 初始化基础布局
installDecor();
}
// ...省略n行代码
// Activity的初始布局中的FramLayout,已经完成xml布局的添加
mLayoutInflater.inflate(layoutResID, mContentParent);
// ...省略n行代码
}
installDecor()
初始化一个基础布局:获取DecorView、mContentParent
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
// ... 省略N行代码
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
// ... 省略N行代码
}
}
// 初始化的基础布局也是一个XML文件
protected ViewGroup generateLayout(DecorView decor) {
// ...省略N行代码
//通过findViewById在基础布局中找到ViewGroup
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
// ...省略N行代码
return contentParent;
}
mLayoutInflater.inflate()
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
// ....省略N行代码
// 获取XmlResourceParser,用于解析XML
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
// ...省略N行代码
// Temp is the root view that was found in the xml
// 找到XMl根视图
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
// ...省略N行代码
// to root. Do that now.
if (root != null && attachToRoot) {
// addView
root.addView(temp, params);
}
return result;
}
}
到这里完成了第一步:
setContentView为XML加载到UI做了哪些准备工作?
setContentView之后Activity如何开始运转工作的?
在
ActivityThread
中调用
performLaunchActivity()
会完成
Activity的启动
以及
setContentView设置
,会得到Activity对象。
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
// ....省略
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
}
// 无用代码不再贴出
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
//...省略N行
ViewManager wm = a.getWindowManager();
wm.addView(decor, l);
}
从开始运转工作到测量绘制布局做了哪些工作?
这里都是代码的跳转不在一一贴源码,直接看图即可。
ActivityThread类:
handleResumeActivity()
=>
WindowManagerImpl类:
addView()
=>
WindowManagerGlobal类:
addView()
=>
ViewRootImpl类:
setView()
=>
这里会触发启动,将参数和视图交给ViewRootlmpl
ViewRootImpl类:
requestLayout()
=>
scheduleTraversals()
=>
doTraversal()
=>
performTraversals()
开始真正的
测量、布局、绘制
补充:
view.assignParent(this);
给View分配Parent,这里传的this,说明view的parent就是ViewRootIml
这里就是吧自己分配给自己的子View.这也是mParent的由来
总结
- 在Activity创建后,调用setContentView设置XML,主要加载了一个基础布局(基础布局也是一个XML),
完成顶层DecorView、和mContentParent容器的初始化
- 后调用inflate(),
通过XmlResourceParser去解析设置的XML
- 通过
找到布局根视图,将其添加到createViewFromTag
容器中mContentParent
- 然后handleResumeActivity中获取
,调用ViewManager
开始Activity的运转addView
- 层层调用,会在WindowManagerGlobal类中调用ViewRootImpl中的
setView触发启动
- setView中调用
,最终会调到requestLayout()
performTraversals()
- 最后performTraversals()
完成最后的=> performMeasure()=> performLayout()=>performDraw()
测量、布局、绘制
到这里就已经完成
xml如何通过加载到UI界面
后续会继续分析,是如何测量、布局、绘制。
Thanks!