美文网首页
setContentView之后

setContentView之后

作者: only_run | 来源:发表于2019-11-01 18:05 被阅读0次

开发中定义的xml布局文件 是通过setContentView(R.layout.xx)加载给Activity的,那么setContentView方法调用之后发生了什么?

setContentView调用

//AppCompatActivity
 public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);//1
    }

//AppCompatDelegateImpl
 public void setContentView(int resId) {
        ensureSubDecor();//2
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);//3
        contentParent.removeAllViews();
        LayoutInflater.from(mContext).inflate(resId, contentParent);//4
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }

注释1 就一行代码 getDelegate实际获取的是AppCompatDelegateImpl对象,接着调用AppCompatDelegateImpl的setContentView方法
接着调用 注释2 先创建DecorView,然后根据Activity主题 加载不同layout布局创建subDecor添加到DecorView(后面详细描述)
注释3 获取subDecor的contentParent 作为用户布局的parent 在注释4 加载用户布局 到contentParent

ensureSubDecor调用

//AppCompatDelegateImpl
private void ensureSubDecor() {
        if (!mSubDecorInstalled) {
            mSubDecor = createSubDecor();
          ...
    }
private ViewGroup createSubDecor() {
        TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);

        if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) {
            a.recycle();
            throw new IllegalStateException(
                    "You need to use a Theme.AppCompat theme (or descendant) with this activity.");
        }

        if (a.getBoolean(R.styleable.AppCompatTheme_windowNoTitle, false)) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
        } else if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBar, false)) {
            // Don't allow an action bar if there is no title.
            requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR);
        }
        if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBarOverlay, false)) {
            requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY);
        }
        if (a.getBoolean(R.styleable.AppCompatTheme_windowActionModeOverlay, false)) {
            requestWindowFeature(FEATURE_ACTION_MODE_OVERLAY);
        }
        mIsFloating = a.getBoolean(R.styleable.AppCompatTheme_android_windowIsFloating, false);
        a.recycle();

        // Now let's make sure that the Window has installed its decor by retrieving it
        ensureWindow();
        mWindow.getDecorView();//1

        final LayoutInflater inflater = LayoutInflater.from(mContext);
        ViewGroup subDecor = null;


        if (!mWindowNoTitle) {
            if (mIsFloating) {
                // If we're floating, inflate the dialog title decor
                subDecor = (ViewGroup) inflater.inflate(
                        R.layout.abc_dialog_title_material, null);//2

                // Floating windows can never have an action bar, reset the flags
                mHasActionBar = mOverlayActionBar = false;
            } else if (mHasActionBar) {
                /**
                 * This needs some explanation. As we can not use the android:theme attribute
                 * pre-L, we emulate it by manually creating a LayoutInflater using a
                 * ContextThemeWrapper pointing to actionBarTheme.
                 */
                TypedValue outValue = new TypedValue();
                mContext.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true);

                Context themedContext;
                if (outValue.resourceId != 0) {
                    themedContext = new ContextThemeWrapper(mContext, outValue.resourceId);
                } else {
                    themedContext = mContext;
                }

                // Now inflate the view using the themed context and set it as the content view
                subDecor = (ViewGroup) LayoutInflater.from(themedContext)
                        .inflate(R.layout.abc_screen_toolbar, null);//3

                mDecorContentParent = (DecorContentParent) subDecor
                        .findViewById(R.id.decor_content_parent);
                mDecorContentParent.setWindowCallback(getWindowCallback());

               ...
        } else {
            if (mOverlayActionMode) {
                subDecor = (ViewGroup) inflater.inflate(
                        R.layout.abc_screen_simple_overlay_action_mode, null);//4
            } else {
                subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);//5
            }
            ...
        }
        ...
        // Now set the Window's content view with the decor
        mWindow.setContentView(subDecor);//6
        ...
        return subDecor;
    }

注释1 获取DecorView 如果为空创建,getDecorView这个方法实际实现是在WindowManagerImpl 这里不再深究了 需要下载android9.0的源码追踪一下;
注释2 ,3 ,4,5 都是根据theme属性配置 读取对应的布局文件 创建对应的View对象 subDecor ,例如注释3 的执行添加是 mHasActionBar 是否存在ActionBar 是不是很熟悉;
注释6 mWindow把subDecor作为DecorView 的子View 进行add;
整理view层级结构如下


根布局结构图.png

相关文章

网友评论

      本文标题:setContentView之后

      本文链接:https://www.haomeiwen.com/subject/jraovctx.html