SetContentView源码解析

1、setContentView作用

Set the activity content from a layout resource. The resource will be
inflated, adding all top-level views to the activity.

将布局资源文件设置activity上的内容,资源将会被渲染,添加到activity的顶级视图

2、源码分析

通过一个Activity的setContentView()方法展开

 public void setContentView(@LayoutRes int layoutResID) {
        // 通过window设置内容
        getWindow().setContentView(layoutResID);
        // 初始化ActionBar
        initWindowDecorActionBar();
    }

getWindow().setContentView(layoutResID);

通过getWindow()方法,获取window对象,并调用Window类中的setContentView(layoutResID)方法

 public Window getWindow() {
        return mWindow;
    }

那么mWindow从哪里进行赋值的呢?

查看Activity源码中的attach方法,发现
mWindow = new PhoneWindow(this, window, activityConfigCallback);
可见那么mWindow是通过PhoneWindow来赋值的

 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);

Window类中的setContentView(layoutResID)方法

通过源码查看该方法是一个abstract方法,必然由其子类重写来实现具体操作

    public abstract void setContentView(@LayoutRes int layoutResID);

PhoneWindow源码查看

public class PhoneWindow extends Window implements MenuBuilder.Callback {

果然PhoneWindow是Window的子类,需要重写SetContentView()方法

setContentView(layoutResID)

    @Override
    public void setContentView(int layoutResID) {
        // mContentParent判空
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        // 没有FEATURE_CONTENT_TRANSITIONS属性移除mContentParent中所有的views
            mContentParent.removeAllViews();
        }

        // 如果具有FEATURE_CONTENT_TRANSITIONS属性
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        // 通过mContentParent、layoutResID、context获取Scence对象
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            // 调用transitionTo方法将scence对象传递      
            transitionTo(newScene);
        } else {
            // 渲染资源文件
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        // 请求插入
        mContentParent.requestApplyInsets();
        //获取回调
        final Callback cb = getCallback();
        // 如果拥有回调并且未被销毁
        if (cb != null && !isDestroyed()) {
        // 回调contentChanged方法
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

installDecor();

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
        // 生成mDecor也就是DecorView
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
        // 将当前phoneWindow设置给decorView
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            // 如果mContentParent为空,通过decor对象生成mContentParent
            mContentParent = generateLayout(mDecor);
            mDecor.makeOptionalFitsSystemWindows();
            final DecorContentParent decorContentParent = (DecorContentParent)
            // 通过id查询控件获取decorContentParent
            mDecor.findViewById(
                    R.id.decor_content_parent);

            if (decorContentParent != null) {
                // 设置decorContentParent相关属性
            } else {
                // 设置title
                // 根据style设置各种属性
    }

generateDecor(-1);

 protected DecorView generateDecor(int featureId) {
        Context context;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext().getResources());
                if (mTheme != -1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        // 根据context、featureId、phoneWindow、attr创建decorView对象
        return new DecorView(context, featureId, this, getAttributes());
    }

generateLayout(mDecor);

  protected ViewGroup generateLayout(DecorView decor) {
       // 获取typeArray对象
        TypedArray a = getWindowStyle();
        // 读取style属性
        // requestFeature
        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        // 省略部分相似功能代码......

        // 根据属性设置Flag
        if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
        }
        // 省略部分相似功能代码......


        // 设置状态栏颜色属性
        if (!mForcedStatusBarColor) {
            mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
        }
        // 设置导航栏属性
        if (!mForcedNavigationBarColor) {
            mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
            mNavigationBarDividerColor = a.getColor(R.styleable.Window_navigationBarDividerColor,
                    0x00000000);
        }
        // 获取LayoutParams
        WindowManager.LayoutParams params = getAttributes();


        // 设置params属性
        if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
                mIsFloating)) {
            /* All dialogs should have the window dimmed */
            if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
                params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
            }
            if (!haveDimAmount()) {
                params.dimAmount = a.getFloat(
                        android.R.styleable.Window_backgroundDimAmount, 0.5f);
            }
        }

        if (params.windowAnimations == 0) {
            params.windowAnimations = a.getResourceId(
                    R.styleable.Window_windowAnimationStyle, 0);
        }
        // 渲染decorView
        // Inflate the window decor.

        int layoutResource;
        int features = getLocalFeatures();
        // 根据features获取resource资源
        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            layoutResource = R.layout.screen_swipe_dismiss;
            setCloseOnSwipeEnabled(true);
        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleIconsDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_title_icons;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
            // System.out.println("Title Icons!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
            // Special case for a window with only a progress bar (and title).
            // XXX Need to have a no-title version of embedded windows.
            layoutResource = R.layout.screen_progress;
            // System.out.println("Progress!");
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
            // Special case for a window with a custom title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogCustomTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_custom_title;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
                layoutResource = a.getResourceId(
                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
                        R.layout.screen_action_bar);
            } else {
                layoutResource = R.layout.screen_title;
            }
            // System.out.println("Title!");
        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
            layoutResource = R.layout.screen_simple_overlay_action_mode;
        } else {
            // Embedded, so no decoration is needed.
            layoutResource = R.layout.screen_simple;
            // System.out.println("Simple!");
        }
        // 开始改变decorView
        mDecor.startChanging();
        // 根据资源文件和mLayoutInflater将资源文件加载到decorView上
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }

        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
            ProgressBar progress = getCircularProgressBar(false);
            if (progress != null) {
                progress.setIndeterminate(true);
            }
        }

        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            registerSwipeCallbacks(contentParent);
        }

        // Remaining setup -- of background and title -- that only applies
        // to top-level windows.
        if (getContainer() == null) {
            final Drawable background;
            if (mBackgroundResource != 0) {
                background = getContext().getDrawable(mBackgroundResource);
            } else {
                background = mBackgroundDrawable;
            }
            // 设置背景
            mDecor.setWindowBackground(background);

            final Drawable frame;
            if (mFrameResource != 0) {
                frame = getContext().getDrawable(mFrameResource);
            } else {
                frame = null;
            }
            // 设置frame结构
            mDecor.setWindowFrame(frame);
            // 设置阴影
            mDecor.setElevation(mElevation);
            // 设置限定范围
            mDecor.setClipToOutline(mClipToOutline);

            if (mTitle != null) {
                setTitle(mTitle);
            }

            if (mTitleColor == 0) {
                mTitleColor = mTextColor;
            }
            setTitleColor(mTitleColor);
        }
        // 改变结束
        mDecor.finishChanging();
        // 返回viewGroup
        return contentParent;
    }

3、流程图
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值