setContentView() 初始化


一、初始化布局

窗体是视图的容器,手机平台窗体是 PhoneWindow 类。
在 package com.android.internal.policy 包中,定义 /** @hide */ DecorView 类,树结构的根视图类型,继承 FrameLayout 类。
在 Activity 类的 attach() 方法,初始化内部 mWindow,即创建 PhoneWindow 对象。

public PhoneWindow(Context context) {
    super(context);
    mLayoutInflater = LayoutInflater.from(context);
}

创建布局解析器 LayoutInflater 类。
在 Activity 类的 onCreate() 方法,通常 setContentView() 方法 设置布局文件,资源 id 是 R.layout.xxx。

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

调用 Window 的 setContentView() 方法。

private DecorView mDecor;//根View
private ViewGroup mContentParent;//存放解析出外部的View
private ViewGroup mContentRoot;//mDecor的直接子View

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        //初始化mDecor,创建mContentRoot和mContentParent
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
       mContentParent.removeAllViews();
    }
    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        ...
    } else {
        //解析资源ID的View加入到mContentParent的子View中去
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

Window 内部 包含 DecorView。
installDecor() 方法,初始化 DecorView,创建 mContentRoot 和 mContentParent

mContentRoot 是 inflate() xml 文件的视图,添加到顶层视图。

//PhoneWindow的generateLayout方法。mContentRoot创建的代码段。
View in = mLayoutInflater.inflate(layoutResource, null);
//加入顶层视图。
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;

系统框架根据 Window 不同 Feature ,选择不同的 layoutResource 布局资源解析,将解析 View 添加到 DecorView 子视图。
举例一种最简单 screen_simple.xml 文件。


    
    

mContentParent 视图,通过 findViewById() 方法。
解析资源 id 节点 com.android.internal.R.id.content,FrameLayout 类型。

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
setContentView() 初始化_第1张图片
树形结构视图

二、XML 解析

LayoutInflater 类,解析 xml 类型 layout 布局文件。

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

根据 int 类型的 resource,生成一个 XmlResourceParser 对象。

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        final Context inflaterContext = mContext;
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        mConstructorArgs[0] = inflaterContext;
        View result = root;
        try {
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                    type != XmlPullParser.END_DOCUMENT) {
                // Empty
            }
            final String name = parser.getName();
            
            if (TAG_MERGE.equals(name)) {
                ...
            } else {
                final View temp = createViewFromTag(root, name, inflaterContext, attrs);
                ViewGroup.LayoutParams params = null;
                if (root != null) {

                    params = root.generateLayoutParams(attrs);
                    if (!attachToRoot) {
                        temp.setLayoutParams(params);
                    }
                }
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }

                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }
        } catch (XmlPullParserException e) {
        } catch (Exception e) {
        } finally {
        }
        return result;
    }
}

XmlPullParser 负责解析 xml 文件,根据 Tag 生成 View 对象。
addView() 方法,将生成的视图添加到 root ,即 mContentParent 视图。

三、总结

DecorView 类,树结构顶层视图类。

mContentRoot 视图,根据 Android_SDK 资源布局 xml 文件解析的视图。

mContentParent ,FrameLayout 类型,mContentRoot 的一个子视图,装载 setContentView() 方法 资源 layout id 视图布局,该视图还包含其他子视图,例如 ActionBar,装载到 ViewStub 节点。

setContentView() 方法,负责 layout 初始化,实现树视图结构,未进行视图测量、布局和绘制。


任重而道远

你可能感兴趣的:(setContentView() 初始化)