Activity:xml如何通过加载到UI界面

版本:27.1.1
观看目录:

  1. Activity:启动流程
  2. Activity:xml如何通过加载到UI界面

结合Activity:启动流程的流程图:

如果对Activity的启动流程不熟悉的请移步:Activity:启动流程

下图是从Activity启动XML如何加载到UI界面的:

图有点大,可以点击图片放大查看:

建议跟着源码过一遍流程图熟悉下,在看更容易理解!
Activity:xml如何通过加载到UI界面_第1张图片

本文章分析流程图

截选自上图后半部分。
Activity:xml如何通过加载到UI界面_第2张图片

本文分析分三个方面来说:

  1. setContentView为XML加载到UI做了哪些准备工作?
  2. setContentView之后Activity如何开始运转工作的?
  3. 从开始运转工作到测量绘制布局做了哪些工作?

setContentView

Activity:xml如何通过加载到UI界面_第3张图片
源码: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);

    }

从开始运转工作到测量绘制布局做了哪些工作?

Activity:xml如何通过加载到UI界面_第4张图片
这里都是代码的跳转不在一一贴源码,直接看图即可。

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的由来

总结

  1. 在Activity创建后,调用setContentView设置XML,主要加载了一个基础布局(基础布局也是一个XML),完成顶层DecorView、和mContentParent容器的初始化
  2. 后调用inflate(),通过XmlResourceParser去解析设置的XML
  3. 通过createViewFromTag找到布局根视图,将其添加到mContentParent容器中
  4. 然后handleResumeActivity中获取ViewManager,调用addView开始Activity的运转
  5. 层层调用,会在WindowManagerGlobal类中调用ViewRootImpl中的setView触发启动
  6. setView中调用 requestLayout(),最终会调到performTraversals()
  7. 最后performTraversals()=> performMeasure()=> performLayout()=>performDraw() 完成最后的测量、布局、绘制

到这里就已经完成xml如何通过加载到UI界面

后续会继续分析,是如何测量、布局、绘制。

Thanks!

你可能感兴趣的:(Activty)