天天看点

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

版本:27.1.1

观看目录:

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

结合

Activity:启动流程

的流程图:

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

下图是从

Activity启动

XML如何加载到UI界面

的:

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

建议跟着源码过一遍流程图熟悉下,在看更容易理解!

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

本文章分析流程图

截选自上图后半部分。

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

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

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

setContentView

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

源码: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界面

这里都是代码的跳转不在一一贴源码,直接看图即可。

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!

继续阅读