【第22期】观点:IT 行业加班,到底有没有价值?

setContentView()源码的理解

原创 2016年05月30日 21:05:47

setContentView()源码的理解

通俗的解释

使用场景

在Activity中的onCreate()方法中,我们会使用setContentView()给Activity加载布局。但实际情况却不是我们通常使用时理解的那样。正如setContentView()方法名那样,是将layout设置给content,而不是设置给Activity。

先放结论

Activity的布局是有特定的模板,我们通常只是给Content区域填充View
以screen_custom_title.xml模板为例(查看源码请按这里),会得到下图

这里写图片描述
简单梳理一下执行流程:

Created with Raphaël 2.1.0setContentView(layout)初始化DecorView(FrameLayout)根据情况初始化相应的ViewGroup将ViewGroup添加到DecorView中在ViewGroup中找到Content(FrameLayout)对象将Layout填充到Content中其他操作

以findViewById()为例,来进一步理解

在Activity中,我们使用findViewById()都很熟练,感觉没什么特别的。但是在Framework中,想要找到特定的控件对象,会使用

view.findViewById(id);

来获取相应的控件。实际上,findViewById()是View当中的方法在Activity中,findViewById()实际上是调用DecorView.findViewById(),只是不给使用者展示。也就是说,DecorView是外层的布局,也从侧面验证了上图。

RTFSC解释

为了把握整体思路,这里并没有详细地说明每一行代码

Activity中的相关代码

public void setContentView(@LayoutRes int layoutResID) {
    //会调用PhoneWindow中的代码
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

PhoneWindow中setContentView()相关代码

public void setContentView(int layoutResID) {
    //mContentParent,也就是Content(上图浅紫色,与Title平级的部分)
    if (mContentParent == null) {
        //DecorView会在这里初始化,ViewGroup也在该方法中添加到DecorView中了,同时找打了mContentParent对象
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        //将我们的Layout填充到mContentParent中
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

installDecor()中相关的代码,有省略代码

private void installDecor() {
    if (mDecor == null) {
        //初始化DecorView
        mDecor = generateDecor();
        //一些相关的配置
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    if (mContentParent == null) {
        //将ViewGroup添加到DecorView中,并将Content找到,返回
        mContentParent = generateLayout(mDecor);

        mDecor.makeOptionalFitsSystemWindows();

        //自带装饰的Content
        //DecorContentParent名字起的也很生动,带装饰的
        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if (decorContentParent != null) {
            //对decorContentParent的操作
            //设置logo,title,icon,options...
        } else {
            //对Title的一些操作
            //...
        }

        if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
            mDecor.setBackgroundFallback(mBackgroundFallbackResource);
        }

        // Only inflate or create a new TransitionManager if the caller hasn't
        // already set a custom one.
        if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
            //一些过渡的操作
            //...
        }
    }
}

generateLayout中相关的代码,有省略

protected ViewGroup generateLayout(DecorView decor) {
    //获取相关属性
    TypedArray a = getWindowStyle();

    if (false) {
        //估计是调试用的代码
        //...
    }

    //各种属性的设置
    //...

    //ViewGroup的Layout用的id
    int layoutResource;
    int features = getLocalFeatures();
    //根据设置来确定layoutResource是哪个layout
    //...

    //做个开始标记
    mDecor.startChanging();

    //填充ViewGroup
    View in = mLayoutInflater.inflate(layoutResource, null);
    //将ViewGroup添加到DecorView中
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;

    //获取Content对象
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

    //一些操作
    //...

    //做个结束标记
    mDecor.finishChanging();

    //返回ViewGroup
    return contentParent;
}

结语

setContentView()相关的代码还是很多的,需要抓住重点,这样才不会影响整体的思维。
如果看完了还是感觉云里雾里,那就先把图片记住,剩下的以后再说

转载请标明出处:http://blog.csdn.net/qq_26411333/article/details/51541129

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

Android源码解析Activity#setContentView()方法

在Activity初始化的过程中,会调用Activity的attach方法,在该方法中会创建一个PhoneWindow的实例,将其作为Activity的mWindow成员变量。在执行完了Activit...

Android 源码解析 之 setContentView

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41894125,本文出自:【张鸿洋的博客】 大家在平时的开发中,对于setContentView肯定不陌生,那么对其内部的实现会不会比较好奇呢~~~有幸终

程序员升职加薪指南!还缺一个“证”!

CSDN出品,立即查看!

Android Handler、Message完全解析,带你从源码的角度彻底理解

之前也是由于周末通宵看TI3比赛,一直没找到时间写博客,导致已经有好久没更新了。惭愧!后面还会恢复进度,尽量保证每周都写吧。这里也是先恭喜一下来自瑞典的Alliance战队夺得了TI3的冠军,希望明年中国战队能够虎起! 开始进

Android setContentView()源码解析

Android setContentView()源码解析

Android 源码解析 之 setContentView

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41894125,本文出自:【张鸿洋的博客】 大家在平时的开发中,对于setContentView肯定不陌生,那么对其内部的实现会不会比较好奇呢~~~有幸终
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)