View的加载流程

235 阅读1分钟

1、Activity 中 onCreate()方法中 调用setContentView();

2、setContentView();

实际: AppCompatAcivity中加载View @Override public void setContentView(@LayoutRes int layoutResID) {

 getDelegate().setContentView(layoutResID);

}

@Override public void setContentView(int resId) {

    ensureSubDecor();
    ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
    contentParent.removeAllViews();
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    mOriginalWindowCallback.onContentChanged();

}

private void ensureSubDecor() { if (!mSubDecorInstalled) { mSubDecor = createSubDecor();

        // If a title was set before we installed the decor, propagate it now
        CharSequence title = getTitle();
        if (!TextUtils.isEmpty(title)) {
            onTitleChanged(title);
        }

        applyFixedSizeWindow();

        onSubDecorInstalled(mSubDecor);

        mSubDecorInstalled = true;

        // Invalidate if the panel menu hasn't been created before this.
        // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
        // being called in the middle of onCreate or similar.
        // A pending invalidation will typically be resolved before the posted message
        // would run normally in order to satisfy instance state restoration.
        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
        if (!isDestroyed() && (st == null || st.menu == null)) {
            invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR);
        }
    }
}

private ViewGroup createSubDecor() {

  ........
  // Now set the Window's content view with the decor
    mWindow.setContentView(subDecor);

 ........
    return subDecor;

}

Activity 中的 public void setContentView(@LayoutRes int layoutResID) {

 getWindow().setContentView(layoutResID);
 initWindowDecorActionBar();

}

Window 是在 Activity中的attach中直接new PhoneWindow()出来的

LayoutInflater 在PhoneWindow构造函数中 new 出来的; public PhoneWindow(Context context) {

    super(context);
    mLayoutInflater = LayoutInflater.from(context);

}

XmlResourceParser 使用的是Pull解析

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root,boolean attachToRoot) {

    final Resources res = getContext().getResources();
    if (DEBUG) {
        Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                + Integer.toHexString(resource) + ")");
    }

    final XmlResourceParser parser = res.getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

XmlResourceParser通过Pull解析,获取节点,得到节点的控件名,通过反射生成View控件,递归生成View添加ViewGroup中

总结: 1.通过Activity的setContentView方法间接调用Phonewindow的setContentView(),在PhoneWindow中通过getLayoutInflate()得到LayoutInflate对象

2.通过LayoutInflate对象去加载View,主要步骤是

(1)通过xml的Pull方式去解析xml布局文件,获取xml信息,并保存缓存信息,因为这些数据是静态不变的

(2)根据xml的tag标签通过反射创建View逐层构建View

(3)递归构建其中的子View,并将子View添加到父ViewGroup中;