What is DecorView and android.R.id.content?

Posted by 夏敏的博客 on March 11, 2017

引言

DecorView和android.R.id.content是什么呢,我们必须从最常见的setContentView这个方法说起。
很多人都知道android.R.id.content,那么他是哪来的呢?我们看完文章就知道了。
大家都知道这个方法

setContentView(R.layout.activity_main);

设置我们的Activity的显示布局,但是大家知道这个布局是怎么显示的呢?
我们看Activity源码中的方法

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

那这个 getWindow() 是什么呢 我们看源代码,在Activity的6619行和890行

 mWindow = new PhoneWindow(this, window);

 public Window getWindow() {
    return mWindow;
 }

所以我们拿到的是PhoneWindow

PhoneWindow.setContentView

public void setContentView(int layoutResID) {  
    if (mContentParent == null) {  
        installDecor();  
    } else {  
        mContentParent.removeAllViews();  
    }  
    mLayoutInflater.inflate(layoutResID, mContentParent);  
    final Callback cb = getCallback();  
    if (cb != null && !isDestroyed()) {  
        cb.onContentChanged();  
    }  
  }  

  private void installDecor() {  
            if (mDecor == null) {  
                mDecor = generateDecor();  
                mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);  
                mDecor.setIsRootNamespace(true);  
                //...  
                }  
            }  
            if (mContentParent == null) {  
                mContentParent = generateLayout(mDecor);  
                mTitleView = (TextView)findViewById(com.android.internal.R.id.title);  
                if (mTitleView != null) {  
                   //根据FEATURE_NO_TITLE隐藏,或者设置mTitleView的值  
                    //...  
                } else {  
                    mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);  
                    if (mActionBar != null) {  
                        //设置ActionBar标题、图标神马的;根据FEATURE初始化Actionbar的一些显示  
                        //...  
                    }  
                }  
            }  
    }

  protected DecorView generateDecor() {  
        return new DecorView(getContext(), -1);  
  }  

mDecor是DecorView对象,为FrameLayout的子类,再通过 generateLayout(mDecor);把mDecor做为参数传入,然后获取到了我们的mContentParent;

看几行总要的代码。将layoutResource资源渲染之后,添加进了我们的decor里面了。

layoutResource = R.layout.simple;
View in = mLayoutInflater.inflate(layoutResource, null);  
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  

R.layout.simple

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:fitsSystemWindows="true">  
    <!-- Popout bar for action modes -->  
    <ViewStub android:id="@+id/action_mode_bar_stub"  
              android:inflatedId="@+id/action_mode_bar"  
              android:layout="@layout/action_mode_bar"  
              android:layout_width="match_parent"  
              android:layout_height="wrap_content" />  

    <FrameLayout android:id="@android:id/content"  
        android:layout_width="match_parent"   
        android:layout_height="0dip"  
        android:layout_weight="1"  
        android:foregroundGravity="fill_horizontal|top"  
        android:foreground="?android:attr/windowContentOverlay" />  
</LinearLayout>

我们看的是,系统将我们传过来的布局渲染了然后添加到decor里面。那么decor的作用就显示出了,是DecorView这个帧布局是存放我们的根试图的。试图里面有一个布局是存放actionbar的,另一个是大名鼎鼎的android.R.id.content。而且是个帧布局哦。

所以

所以我们知道了,android.R.id.content是个帧布局啊。我们以后添加view,没有必要一定要使用popWindow这类的东西,能够直接往我们的android.R.id.content主布局添加东西了啊。

而DecorView呢,我们平时的getDecorView:这个方法是获取顶级视图,里面是包含了我们的android.R.id.content的,而且也是个帧布局哦。我们甚至也能addView。

接下来,下一篇打算写一个低耦合的SnackView,我们已经知道往哪边添加这个View拉。


谢谢大家阅读,如有帮助,来个喜欢或者关注吧!


本文作者:Anderson/Jerey_Jobs

博客地址 : 夏敏的博客/Anderson大码渣/Jerey_Jobs
简书地址 : Anderson大码渣
github地址 : Jerey_Jobs

作者:Anderson大码渣,欢迎关注我的简书: Anderson大码渣