版本:27.1.1
观看目录:
Activity:启动流程
的流程图:如果对Activity的启动流程不熟悉的请移步:Activity:启动流程
下图是从Activity启动
到XML如何加载到UI界面
的:
图有点大,可以点击图片放大查看:
本文分析分三个方面来说:
源码:PhoneWindow中的setContentView
// 只保留两个核心方法
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
// 初始化基础布局
installDecor();
}
// ...省略n行代码
// Activity的初始布局中的FramLayout,已经完成xml布局的添加
mLayoutInflater.inflate(layoutResID, mContentParent);
// ...省略n行代码
}
初始化一个基础布局:获取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;
}
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做了哪些准备工作?
在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的由来
完成顶层DecorView、和mContentParent容器的初始化
通过XmlResourceParser去解析设置的XML
createViewFromTag
找到布局根视图,将其添加到mContentParent
容器中ViewManager
,调用addView
开始Activity的运转setView触发启动
requestLayout()
,最终会调到performTraversals()
=> performMeasure()=> performLayout()=>performDraw()
完成最后的测量、布局、绘制
到这里就已经完成xml如何通过加载到UI界面
后续会继续分析,是如何测量、布局、绘制。
Thanks!