• 【转】decorView和window之间的层级及关系


    转载请注明出处:http://blog.csdn.net/guxiao1201/article/details/41744107

    首先贴出实现Activity对话框圆角的核心代码

    [java] view plain copy
     
    1. @Override  
    2.     public void onAttachedToWindow() {  
    3.         super.onAttachedToWindow();  
    4.         DisplayMetrics dm = new DisplayMetrics();  
    5.         getWindowManager().getDefaultDisplay().getMetrics(dm);  
    6.         View view = getWindow().getDecorView();  
    7.         WindowManager.LayoutParams lp = (WindowManager.LayoutParams)view.getLayoutParams();  
    8.         lp.gravity = Gravity.CENTER;  
    9.         lp.width = (dm.widthPixels * 4) / 5;  
    10.         lp.height = (dm.widthPixels * 4) / 5;  
    11.         getWindowManager().updateViewLayout(view,lp);  
    12.         getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));  
    13.         view.setBackgroundResource(R.drawable.dialog_activity_bg);  
    14.     }  

    在上篇博客onAttachedToWindow()在整个Activity生命周期的位置及使用中解释了为什么在onAttachedToWindow中修改窗口尺寸,上面代码最后两行分别对window和decorView设置背景,那么问题来了,一个窗体中decorView和window之间的关系是什么?

    通过文章开始贴出的代码View view = getWindow().getDecorView();就可以对Window和DecorView的层级关键猜测一二,decorView是否作为一个变量由window维护?
    和之前思路一样,想探究这个问题就得看源码说话。这里依然参考老罗的博客Android应用程序窗口(Activity)的视图对象(View)的创建过程分析

    既然猜测decorView是window的变量,那么就先找到window和activity之间的关系。通过源码发现

    [java] view plain copy
     
    1. public class Activity extends ContextThemeWrapper    
    2.         implements LayoutInflater.Factory,    
    3.         Window.Callback, KeyEvent.Callback,    
    4.         OnCreateContextMenuListener, ComponentCallbacks {    
    5.     ......    
    6.     
    7.     private Window mWindow;    
    8.     ......    
    9.     
    10.     public Window getWindow() {    
    11.         return mWindow;    
    12.     }    
    13.     ......    
    14.     
    15.     public void setContentView(int layoutResID) {    
    16.         getWindow().setContentView(layoutResID);    
    17.     }    
    18.     
    19.     ......    
    20. }    

    Window原来是Activity的一个变量,可以通过getWindow()获取,而且Activity中经常用到的setContentView原来调用的是window的setContentView。那么Window是什么?在Activity中起什么作用?OK~带着问题再查阅Google的官方文档。

    Abstract base class for a top-level window look and behavior policy. An instance of this class should be used as the top-level view added to the window manager. It provides standard UI policies such as a background, title area, default key processing, etc.

    The only existing implementation of this abstract class is Android.policy.PhoneWindow, which you should instantiate when needing a Window. Eventually that class will be refactored and a factory method added for creating Window instances without knowing about a particular implementation.

    Google说Window是WindowManager最顶层的视图,它负责背景(窗口背景)、Title之类的标准的UI元素,Window是一个抽象类,整个Android系统中PhoneWindow是Winodw的唯一实现类。所以接下来进入PhoneWinodw一探究竟。

    [java] view plain copy
     
    1. public class PhoneWindow extends Window implements MenuBuilder.Callback {    
    2.     ......    
    3.     
    4.     // This is the top-level view of the window, containing the window decor.    
    5.     private DecorView mDecor;    
    6.     ......    
    7.     
    8.     // This is the view in which the window contents are placed. It is either    
    9.     // mDecor itself, or a child of mDecor where the contents go.    
    10.     private ViewGroup mContentParent;    
    11.     ......    
    12.     
    13.     private TextView mTitleView;    
    14.     ......    
    15.     
    16.     private CharSequence mTitle = null;    
    17.     ......    
    18.     
    19.     private void installDecor() {    
    20.         if (mDecor == null) {    
    21.             mDecor = generateDecor();    
    22.             ......    
    23.         }    
    24.         if (mContentParent == null) {    
    25.             mContentParent = generateLayout(mDecor);    
    26.     
    27.             mTitleView = (TextView)findViewById(com.android.internal.R.id.title);    
    28.             if (mTitleView != null) {    
    29.                 if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {    
    30.                     View titleContainer = findViewById(com.android.internal.R.id.title_container);    
    31.                     if (titleContainer != null) {    
    32.                         titleContainer.setVisibility(View.GONE);    
    33.                     } else {    
    34.                         mTitleView.setVisibility(View.GONE);    
    35.                     }    
    36.                     if (mContentParent instanceof FrameLayout) {    
    37.                         ((FrameLayout)mContentParent).setForeground(null);    
    38.                     }    
    39.                 } else {    
    40.                     mTitleView.setText(mTitle);    
    41.                 }    
    42.             }    
    43.         }    
    44.     }    
    45.     
    46.     ......    
    47. }    

    在这里总算找到了DecorView,和上面猜测的一样,DecorView确实为Window的变量。同时还发现一个名为mContentParent的ViewGroup,那么这个变量的作用是什么?和DecorView有什么关系?带着问题接着往下看。

    PhoneWindow的setContentView方法

    [java] view plain copy
     
    1. @Override  
    2.     public void setContentView(int layoutResID) {  
    3.         if (mContentParent == null) {  
    4.             installDecor();  
    5.         } else {  
    6.             mContentParent.removeAllViews();  
    7.         }  
    8.         mLayoutInflater.inflate(layoutResID, mContentParent);  
    9.         final Callback cb = getCallback();  
    10.         if (cb != null && !isDestroyed()) {  
    11.             cb.onContentChanged();  
    12.         }  
    13.     }  

    在mContentParent为null时会调用installDecor()来创建应用程序窗口视图对象。接着在installDecor()中调用generateLayout为mContentParent赋值。

    [java] view plain copy
     
    1. protected ViewGroup generateLayout(DecorView decor) {  
    2.     // 获取<Activity android:theme=""/>中的theme属性或者代码requestWindowFeature()中指定的Features  
    3.   
    4.     TypedArray a = getWindowStyle();  
    5.   
    6.     if (false) {  
    7.         System.out.println("From style:");  
    8.         String s = "Attrs:";  
    9.         for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) {  
    10.             s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="  
    11.                     + a.getString(i);  
    12.         }  
    13.         System.out.println(s);  
    14.     }  
    15.   
    16.     mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);  
    17.     int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)  
    18.             & (~getForcedWindowFlags());  
    19.     if (mIsFloating) {  
    20.         setLayout(WRAP_CONTENT, WRAP_CONTENT);  
    21.         setFlags(0, flagsToUpdate);  
    22.     } else {  
    23.         setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);  
    24.     }  
    25.   
    26.     //...  
    27.   
    28.   
    29.     // Inflate the window decor.  
    30.   
    31.     int layoutResource;  
    32.     int features = getLocalFeatures();  
    33.     // System.out.println("Features: 0x" + Integer.toHexString(features));  
    34.     if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {  
    35.         if (mIsFloating) {  
    36.             TypedValue res = new TypedValue();  
    37.             getContext().getTheme().resolveAttribute(  
    38.                     com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);  
    39.             layoutResource = res.resourceId;  
    40.         } else {  
    41.             layoutResource = com.android.internal.R.layout.screen_title_icons;  
    42.         }  
    43.         // XXX Remove this once action bar supports these features.  
    44.         removeFeature(FEATURE_ACTION_BAR);  
    45.         // System.out.println("Title Icons!");  
    46.     } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0  
    47.             && (features & (1 << FEATURE_ACTION_BAR)) == 0) {  
    48.         // Special case for a window with only a progress bar (and title).  
    49.         // XXX Need to have a no-title version of embedded windows.  
    50.         layoutResource = com.android.internal.R.layout.screen_progress;  
    51.         // System.out.println("Progress!");  
    52.     } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {  
    53.         // Special case for a window with a custom title.  
    54.         // If the window is floating, we need a dialog layout  
    55.         if (mIsFloating) {  
    56.             TypedValue res = new TypedValue();  
    57.             getContext().getTheme().resolveAttribute(  
    58.                     com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true);  
    59.             layoutResource = res.resourceId;  
    60.         } else {  
    61.             layoutResource = com.android.internal.R.layout.screen_custom_title;  
    62.         }  
    63.         // XXX Remove this once action bar supports these features.  
    64.         removeFeature(FEATURE_ACTION_BAR);  
    65.     } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {  
    66.         // If no other features and not embedded, only need a title.  
    67.         // If the window is floating, we need a dialog layout  
    68.         if (mIsFloating) {  
    69.             TypedValue res = new TypedValue();  
    70.             getContext().getTheme().resolveAttribute(  
    71.                     com.android.internal.R.attr.dialogTitleDecorLayout, res, true);  
    72.             layoutResource = res.resourceId;  
    73.         } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {  
    74.             layoutResource = com.android.internal.R.layout.screen_action_bar;  
    75.         } else {  
    76.             layoutResource = com.android.internal.R.layout.screen_title;  
    77.         }  
    78.         // System.out.println("Title!");  
    79.     } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {  
    80.         layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;  
    81.     } else {  
    82.         // Embedded, so no decoration is needed.  
    83.         layoutResource = com.android.internal.R.layout.screen_simple;  
    84.         // System.out.println("Simple!");  
    85.     }  
    86.   
    87.     mDecor.startChanging();  
    88.   
    89.     View in = mLayoutInflater.inflate(layoutResource, null);  
    90.     decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
    91.   
    92.     ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  
    93.     if (contentParent == null) {  
    94.         throw new RuntimeException("Window couldn't find content container view");  
    95.     }  
    96.   
    97.     if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {  
    98.         ProgressBar progress = getCircularProgressBar(false);  
    99.         if (progress != null) {  
    100.             progress.setIndeterminate(true);  
    101.         }  
    102.     }  
    103.   
    104.     // Remaining setup -- of background and title -- that only applies  
    105.     // to top-level windows.  
    106.     if (getContainer() == null) {  
    107.         Drawable drawable = mBackgroundDrawable;  
    108.         if (mBackgroundResource != 0) {  
    109.             drawable = getContext().getResources().getDrawable(mBackgroundResource);  
    110.         }  
    111.         mDecor.setWindowBackground(drawable);  
    112.         drawable = null;  
    113.         if (mFrameResource != 0) {  
    114.             drawable = getContext().getResources().getDrawable(mFrameResource);  
    115.         }  
    116.         mDecor.setWindowFrame(drawable);  
    117.   
    118.         // System.out.println("Text=" + Integer.toHexString(mTextColor) +  
    119.         // " Sel=" + Integer.toHexString(mTextSelectedColor) +  
    120.         // " Title=" + Integer.toHexString(mTitleColor));  
    121.   
    122.         if (mTitleColor == 0) {  
    123.             mTitleColor = mTextColor;  
    124.         }  
    125.   
    126.         if (mTitle != null) {  
    127.             setTitle(mTitle);  
    128.         }  
    129.         setTitleColor(mTitleColor);  
    130.     }  
    131.   
    132.     mDecor.finishChanging();  
    133.   
    134.     return contentParent;  
    135. }  

    上面代码可看到将一些页面特性布局,例如ActionBar、Title等添加到decorView中,并且根据代码ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);可看到原来mContentParent是id="@android:id/content"的ViewGroup。再回到PhoneWindow.setContentView

    [java] view plain copy
     
    1. mLayoutInflater.inflate(layoutResID, mContentParent);  

    原来我们自定义的View都是mContentParent的子View。并且上面这段代码还发现了为什么必须在setContentView之前才能执行requestWindowFeature的彩蛋。

    根据上面所有的猜测和分析,最终发现Window、DecorView和mContentParent的层级关系如下图(如有误请指正)


    参考资料:

    Window窗口布局--DecorView浅析

    Android应用程序窗口(Activity)的视图对象(View)的创建过程分析

    from:http://blog.csdn.net/guxiao1201/article/details/41744107

  • 相关阅读:
    元宵福利 | 不废话,直接送 20 本书
    数据结构与算法——234树
    面试官,别问我 Bit Operation 了!
    推荐三个 VSCode 摸鱼插件
    算法科普:有趣的霍夫曼编码
    面试官,你再问我 Bit Operation 试试?
    知否?知否?情人眼里出代码
    我以为是个正经程序猿,结果是个中二段子精
    30 个跟程序猿有关的成语
    提高技术的九个神器
  • 原文地址:https://www.cnblogs.com/xuan52rock/p/6513173.html
Copyright © 2020-2023  润新知