百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

带你了解Android窗口机制Window、PhoneWindow和DecorView之间的关系

yuyutoo 2024-10-19 11:08 6 浏览 0 评论

作者 | Android开发编程 责编 | 欧阳姝黎

在Android框架中,每个应用界面,都有一个应用级的window。

常用的activity、dialog、Toast等都是通过通过创建window、PhoneWindow来实现,所以其实window我们一直都见到,只是不知道那就是window。

了解window的机制原理,可以更好地了解window,进而更好地了解android是怎么管理屏幕上的view。

这样,当我们需要使用dialog或者popupWindow的时候,可以懂得他背后究竟做了什么,才能够更好的运用dialog、popupWindow等。


window、phonewindow、DecorView 关系


先看图

1、每一个 Activity 都持有一个 Window 对象,

public class Activity extends ContextThemeWrappe{ private Window mWindow;}

但是 Window 是一个抽象类,这里 Android 为 Window 提供了唯一的实现类 PhoneWindow。也就是说 Activity 中的 window 实例就是一个 PhoneWindow 对象。

2、但是 PhoneWindow 终究是 Window,它并不具备多少 View 相关的能力。不过 PhoneWindow 中持有一个 Android 中非常重要的一个 View 对象 Decor(装饰)View,它在 PhoneWindow 中的定义如下:

public class PhoneWindow extends Window{ // This is the top-level view of the window, containing the window decor. private DecorView mDecor; }

3、查看 DecorView 继承关系得知,DecorView 继承自 FrameLayout

public class DecorView extends FrameLayout {}

现在的关系就很明确了,每一个 Activity 持有一个 PhoneWindow 的对象,而一个 PhoneWindow 对象持有一个 DecorView 的实例,所以 Activity 中 View 相关的操作其实大都是通过 DecorView 来完成。


Window


Android手机中所有的视图都是通过Window来呈现的,像常用的Activity,Dialog,PopupWindow,Toast,他们的视图都是附加在Window上的,所以可以这么说 ——Window是View的直接管理者。

源代码如下

public abstract class Window { public abstract @Non View getDecorView(); /** * Retrieve the current decor view, but only if it has already been created; * otherwise returns . * * @return Returns the top-level window decor or . * @see #getDecorView */ public abstract View peekDecorView(); public abstract Bundle saveHierarchyState(); public abstract void restoreHierarchyState(Bundle savedInstanceState); protected abstract void onActive(); @able public <T extends View> T findViewById(@IdRes int id) { return getDecorView().findViewById(id); } /** * Convenience for * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)} * to set the screen content from a layout resource. The resource will be * inflated, adding all top-level views to the screen. * * @param layoutResID Resource ID to be inflated. * @see #setContentView(View, android.view.ViewGroup.LayoutParams) */ public abstract void setContentView(@LayoutRes int layoutResID);}

1、Window的type属性

window是有分类的,不同类别的显示高度范围不同。window也是一样按照高度范围进行分类,他也有一个变量Z-Order,决定了window的高度,Z-Order越大,window越靠近用户,也就显示越高,高度高的window会覆盖高度低的window。window一共可分为三类:

  • 应用程序窗口:应用程序窗口一般位于最底层,Z-Order在1-99

  • 子窗口:子窗口一般是显示在应用窗口之上,Z-Order在1000-1999

  • 系统级窗口:系统级窗口一般位于最顶层,不会被其他的window遮住,如Toast,Z-Order在2000-2999。如果要弹出自定义系统级窗口需要动态申请权限。

Window的flags参数

// 当 Window 可见时允许锁屏public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001;// Window 后面的内容都变暗public static final int FLAG_DIM_BEHIND = 0x00000002;// Window 不能获得输入焦点,即不接受任何按键或按钮事件,例如该 Window 上 有 EditView,点击 EditView 是 不会弹出软键盘的// Window 范围外的事件依旧为原窗口处理;例如点击该窗口外的view,依然会有响应。另外只要设置了此Flag,都将会启用FLAG_NOT_TOUCH_MODALpublic static final int FLAG_NOT_FOCUSABLE = 0x00000008;// 设置了该 Flag,将 Window 之外的按键事件发送给后面的 Window 处理, 而自己只会处理 Window 区域内的触摸事件// Window 之外的 view 也是可以响应 touch 事件。public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;// 设置了该Flag,表示该 Window 将不会接受任何 touch 事件,例如点击该 Window 不会有响应,只会传给下面有聚焦的窗口。public static final int FLAG_NOT_TOUCHABLE = 0x00000010;// 只要 Window 可见时屏幕就会一直亮着public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;// 允许 Window 占满整个屏幕public static final int FLAG_LAYOUT_IN_SCREEN = 0x00000100;// 允许 Window 超过屏幕之外public static final int FLAG_LAYOUT_NO_LIMITS = 0x00000200;// 全屏显示,隐藏所有的 Window 装饰,比如在游戏、播放器中的全屏显示public static final int FLAG_FULLSCREEN = 0x00000400;// 表示比FLAG_FULLSCREEN低一级,会显示状态栏public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;// 当用户的脸贴近屏幕时(比如打电话),不会去响应此事件public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;// 则当按键动作发生在 Window 之外时,将接收到一个MotionEvent.ACTION_OUTSIDE事件。public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;@Deprecated// 窗口可以在锁屏的 Window 之上显示, 使用 Activity#setShowWhenLocked(boolean) 方法代替public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;// 表示负责绘制系统栏背景。如果设置,系统栏将以透明背景绘制,// 此 Window 中的相应区域将填充 Window#getStatusBarColor()和 Window#getNavigationBarColor()中指定的颜色。public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;// 表示要求系统壁纸显示在该 Window 后面,Window 表面必须是半透明的,才能真正看到它背后的壁纸public static final int FLAG_SHOW_WALLPAPER = 0x00100000;window的solfInputMode属性这一部分就是当软件盘弹起来的时候,window的处理逻辑,这在日常中也经常遇到,如:聊天的时候,点击输入框,当软键盘弹起来的时候输入框也会被顶上去。如果你不想被顶上去,也可以设置为被软键盘覆盖。下面介绍一下常见的属性// 没有指定状态,系统会选择一个合适的状态或者依赖于主题的配置public static final int SOFT_INPUT_STATE_UNCHANGED = 1;// 当用户进入该窗口时,隐藏软键盘public static final int SOFT_INPUT_STATE_HIDDEN = 2;// 当窗口获取焦点时,隐藏软键盘public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;// 当用户进入窗口时,显示软键盘public static final int SOFT_INPUT_STATE_VISIBLE = 4;// 当窗口获取焦点时,显示软键盘public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;// window会调整大小以适应软键盘窗口public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;// 没有指定状态,系统会选择一个合适的状态或依赖于主题的设置public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;// 当软键盘弹出时,窗口会调整大小,例如点击一个EditView,整个layout都将平移可见且处于软件盘的上方// 同样的该模式不能与SOFT_INPUT_ADJUST_PAN结合使用;// 如果窗口的布局参数标志包含FLAG_FULLSCREEN,则将忽略这个值,窗口不会调整大小,但会保持全屏。public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;// 当软键盘弹出时,窗口不需要调整大小, 要确保输入焦点是可见的,// 例如有两个EditView的输入框,一个为Ev1,一个为Ev2,当你点击Ev1想要输入数据时,当前的Ev1的输入框会移到软键盘上方// 该模式不能与SOFT_INPUT_ADJUST_RESIZE结合使用public static final int SOFT_INPUT_ADJUST_PAN = 0x20;// 将不会调整大小,直接覆盖在window上public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;

2、window的其他属性

  • x与y属性:指定window的位置

  • alpha:window的透明度

  • gravity:window在屏幕中的位置,使用的是Gravity类的常量

  • format:window的像素点格式,值定义在PixelFormat中

window属性赋值

WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams();windParams.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;TextView view = new TextView(this);getWindowManager.addview(view,windowParams);getWindow().flags = WindowManager.LayoutParams.FLAG_FULLSCREEN; <activity android:windowSoftInputMode="SOFT_INPUT_STATE_VISIBLE" />

PhoneWindow


继承于Window类,是Window类的具体实现,即我们可以通过该类具体去绘制窗口。并且,该类内部包含了一个DecorView对象,该DectorView对象是所有应用窗口(Activity界面)的根View。

简而言之,PhoneWindow类是把一个FrameLayout类即DecorView对象进行一定的包装,将它作为应用窗口的根View,并提供一组通用的窗口操作接口。它是Android中的最基本的窗口系统,每个Activity 均会创建一个PhoneWindow对象,是Activity和整个View系统交互的接口。

public class PhoneWindow extends Window implements MenuBuilder.Callback { private final static String TAG = "PhoneWindow"; final PhoneWindowMenuCallback mContextMenuCallback = new PhoneWindowMenuCallback(this); final TypedValue mMinWidthMajor = new TypedValue(); final TypedValue mMinWidthMinor = new TypedValue(); TypedValue mFixedWidthMajor; TypedValue mFixedWidthMinor; TypedValue mFixedHeightMajor; TypedValue mFixedHeightMinor; // This is the top-level view of the window, containing the window decor. private DecorView mDecor; // When we reuse decor views, we need to recreate the content root. This happens when the decor // view is requested, so we need to force the recreating without introducing an infinite loop. private boolean mForceDecorInstall = false; // This is the view in which the window contents are placed. It is either // mDecor itself, or a child of mDecor where the contents go. ViewGroup mContentParent; // Whether the client has explicitly set the content view. If false and mContentParent is not // , then the content parent was set due to window preservation. private boolean mContentParentExplicitlySet = false; Callback2 mTakeSurfaceCallback; InputQueue.Callback mTakeInputQueueCallback; boolean mIsFloating; private boolean mIsTranslucent; private LayoutInflater mLayoutInflater; private TextView mTitleView; DecorContentParent mDecorContentParent;}

它是Android中的最基本的窗口系统,每个Activity 均会创建一个PhoneWindow对象,是Activity和整个View系统交互的接口。


DecorView


作为顶级View,DecorView一般情况下它内部会包含一个竖直方向的LinearLayout,上面的标题栏(titleBar),下面是内容栏。

通常我们在Activity中通过setContentView所设置的布局文件就是被加载到id为android.R.id.content的内容栏里(FrameLayout)

/** @hide */public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { private static final String TAG = "DecorView"; private static final boolean DEBUG_MEASURE = false; private static final boolean SWEEP_OPEN_MENU = false; // The height of a window which has focus in DIP. private final static int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20; // The height of a window which has not in DIP. private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5; private static final int SCRIM_LIGHT = 0xe6ffffff; // 90% white private Drawable mMenuBackground; private boolean mWatchingForMenu; private int mDownY; ActionMode mPrimaryActionMode; private ActionMode mFloatingActionMode; private ActionBarContextView mPrimaryActionModeView; private PopupWindow mPrimaryActionModePopup; private Runnable mShowPrimaryActionModePopup; private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener; private View mFloatingActionModeOriginatingView; private FloatingToolbar mFloatingToolbar; private ObjectAnimator mFadeAnim; // View added at runtime to draw under the status bar area private View mStatusGuard;}

DecorView它主要有以下功能总结:

  • 作为顶级View,DecorView一般情况下它内部会包含一个竖直方向的LinearLayout,上面的标题栏(titleBar),下面是内容栏。通常我们在Activity中通过setContentView所设置的布局文件就是被加载到id为android.R.id.content的内容栏里(FrameLayout);

  • Dispatch ViewRoot分发来的key、touch、trackball等外部事件;

  • DecorView有一个直接的子View,我们称之为SystemLayout,这个View是从系统的Layout.xml中解析出的,它包含当前UI的风格,如是否带title、是否带processbar等。可以称这些属性为Window decorations;

  • 作为PhoneWindow与ViewRoot之间的桥梁,ViewRoot通过DecorView设置窗口属性。//可以这样获取 View = getWindow().getDecorView();

  • DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。DecorView里面TitleView:标题,可以设置requestWindowFeature(Window.FEATURE_NO_TITLE)取消掉ContentView:是一个id为content的FrameLayout。我们平常在Activity使用的setContentView就是设置在这里,也就是在FrameLayout上;

  • 每一个Activity都包含一个Window对象(dialog,toast 等也是新添加的window对象),而Window是一个抽象类,具体实现是PhoneWindow。在Activity中的setContentView实际上是调用PhoneWindow的setContentView方法。并且PhoneWindow中包含着成员变量DecorView。

总结:

Window类相当于一幅画 ,PhoneWindow为一副山水画(具体概念,我们知道了是谁的、什么性质的画),DecorView则为该山水画的具体内容。DecorView呈现在PhoneWindow上。

相关推荐

Mysql和Oracle实现序列自增(oracle创建序列的sql)

Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...

关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)

概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...

MySQL CREATE TABLE 简单设计模板交流

推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....

mysql学习9:创建数据库(mysql5.5创建数据库)

前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...

MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别

执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...

Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出

在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...

美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍

多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...

汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)

全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...

【推荐】ProAc Response系列扬声器逐个看

有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...

#本站首晒# 漂洋过海来看你 — BLACK&amp;DECKER 百得 BDH2000L无绳吸尘器 开箱

作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...

专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)

Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...

常用半导体中英对照表(建议收藏)(半导体英文术语)

作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...

Fyne Audio F502SP 2.5音路低音反射式落地音箱评测

FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...

有哪些免费的内存数据库(In-Memory Database)

以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...

RazorSQL Mac版(SQL数据库查询工具)

RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...

取消回复欢迎 发表评论: