热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WindowManager体系总结

  WindowManager是Android中一个比较复杂的知识体系,今天来总结总结这方面的体系知识,为了便于理解,文章会使用通俗易懂的语言结合XMind图和一些源码进行一步步分析。

    WindowManager是Android中一个比较复杂的知识体系,今天来总结总结这方面的体系知识,为了便于理解,文章会使用通俗易懂的语言结合XMind图和一些源码进行一步步分析。

一、Window、WindowManager和WMS关系

    Window是这三者的核心,起到了桥梁的作用,她是一个抽象类,主要定义了一些对Window操作的抽象方法。WindowManager主要是管理Window是一个接口类,他继承自ViewManager接口,主要定义了一些对View的操作和一些常量,例如:添加View,移除View,删除View。WMS是WindowManagerServer的缩写,主要是连接WindowManager与Window之间的Binder的通信,即WindowManager通过WMS操作Window。


二、Window的属性

    Window的属性是指Window怎样通过WMS管理Window,这些管理的规则被定义在被定义在WindowManager的内部类LayoutParams中,了解Window的属性能够更好的理解WMS的内部原理。这里主要介绍Window的类型,Window的Flag,Window的软键盘相关模式三大内容。

1、Window的类型

    Window的类型大致包括三类,应用程序窗口,子窗口,系统窗口。每个大类又包含了很多种类型,它们都定义在WindowManager的静态内部类LayoutParams中。接下来对这三种窗口类型进行说明。

    (1)应用程序窗口:对应一个Activity,作用于Activity内部,在WindowManager定义了应用程序窗口TYPE值得类型范围1到99,数值越大说明该Window的等级越高,越在上面显示。
    (2)子窗口:不能独立的存在,必须依附于任何类型的父窗口。例如Dialog等,子窗口的TYPE值范围是1000到1999。
    (3)系统窗口:系统窗口的等级最高为,TYPE值范围为2000到2999。例如Toast、入法窗口、状态栏、系统错误窗口等等。

    注意:窗口可以叠加,显示次序根据TYPE值得顺序排列,依次为:系统窗口,子窗口,应用程序窗口。高的等级可以覆盖低的等级。

2、Window的标志

    Window的标志也就是Flag,用于控制Window的显示,同样被定义在WindowManager的内部类LayoutParams中,包括了很多种这里不进行一一列举了,设置通过通过Window的addFlags方法设置:

    (1)方法一

window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置全屏

    (2)方法二

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    注意:一般的弹窗需要依附于activity,在activity中弹窗可以不用设置flag,依附于应用程序窗口。但是在服务、广播中没有父窗口可以依附。所以不能简单使用这种方式,需要采用系统的弹窗,他的优先级很高,覆盖于应用界面的最高层,并且要设置setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT),否则会崩溃。

3、Window的软键盘相关模式

    Android中窗口与窗口的叠加死很常见的,但是如果叠加的是软键盘很可能就遮盖住了输入框,导致无法输入,这种体验是很差的这时候就需要设置Window的软键盘模式。有两种设置方式,一种是在清单文件Activity中设置,另一种是在代码里面进行设置。

    (1)android:windowSoftInputMode="stateVisible|adjustResize"

    (2)getWindow().setSoftInputMode(WindowManager.LayoutParams.

SOFT_INPUT_ADJUST_PAN);

      各输入模式的值含义:

       stateUnspecified:软键盘的状态并没有指定,系统将选择一个合适的状态或依赖于主题的设置

       stateUnchanged:当这个activity出现时,软键盘将一直保持在上一个activity里的状态,无论是隐藏还是显示

       stateHidden:用户选择activity时,软键盘总是被隐藏

       stateAlwaysHidden:当该Activity主窗口获取焦点时,软键盘也总是被隐藏的

       stateVisible:软键盘通常是可见的

       stateAlwaysVisible:用户选择activity时,软键盘总是显示的状态

       adjustUnspecified:默认设置,通常由系统自行决定是隐藏还是显示

       adjustResize:该Activity总是调整屏幕的大小以便留出软键盘的空间

       adjustPan:当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分


三、Window的添加过程

    WindowManager对Window的操作包括添加、更新、删除三个过程,他是一个接口继承自ViewManager,通过WMS进行操作。

public interface ViewManager {
void addView(View var1, LayoutParams var2);
void updateViewLayout(View var1, LayoutParams var2);
void removeView(View var1);
}

    这个操作包含了两大部分一个是WindowManager的操作过程,另一个是WMS的操作过程,对于应用程序窗口,子窗口,系统窗口的窗口添加过程会有所不同,但是对于WMS处理部分,添加的过程基本上是一样的。


    WindowManager操作Window实际上是对View的操作,这个过程是通过实现类WindowManagerImpl,添加View是通过addView方法进行添加的,这个类在 /frameworks/base/core/java/android/view/WindowManagerImpl.java下,如下:

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

    可以看出Window的添加过程是通过WindowManagerGlobal进行操作的,WindowManagerImpl并没有涉及到实际的操作。找到/frameworks/base/core/java/android/view/WindowManagerGlobal.java这个类中的addView方法,源码比较长,不贴出来了可以看出主要做了如下:

    1、检验传入参数的完整性,并作出调整。

if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
....................................省略部分代码...................................
}

   2、创建ViewRootImpl集合,并且添加View。

private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList();
private final ArrayList mParams =new ArrayList();
private final ArraySet mDyingViews = new ArraySet();
..........................................分割线............................................
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);

    3、通过ViewRootImpl的setView调用requestLayout更新界面,最终会调用WindowSession的addToDisplay方法进行绘制,他的内部会调用WMS完成添加。源码地址/frameworks/base/core/java/android/view/ViewRootImpl.java。

(1)View的绘制

@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
//View的绘制入口
scheduleTraversals();
}
}

(2)View的添加

res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);

   mWindowSession是一个AIDL文件,定义了很多IPC通信通信接口,文件地址/frameworks/base/core/java/android/view/IWindowSession.aidl,真正的实现类是Session类。这个类位于/frameworks/base/services/core/java/com/android/server/wm/Session.java

@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

        上面的mService就是WindowManagerService,这样一来,Window的添加请求就会从这交给WMS处理了。至此Window的添加过程分析结束。以上就是Window的添加过程的主要流程,更新和删除和这个类似,这里不再做分析了。


注:转载请注明,尊重他人的劳动成果。



推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 最近学习反射机制的时候Properties.load(读取本地文件流的时候怎么也找不到加载文件后面发现IDEA的默认根目录是在它的Project工程下IDEA的文件目录和Ec ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
author-avatar
秋知落叶冷
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有