热门标签 | 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的添加过程的主要流程,更新和删除和这个类似,这里不再做分析了。


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



推荐阅读
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 深入理解CSS中的margin属性及其应用场景
    本文主要介绍了CSS中的margin属性及其应用场景,包括垂直外边距合并、padding的使用时机、行内替换元素与费替换元素的区别、margin的基线、盒子的物理大小、显示大小、逻辑大小等知识点。通过深入理解这些概念,读者可以更好地掌握margin的用法和原理。同时,文中提供了一些相关的文档和规范供读者参考。 ... [详细]
  • vb如何去掉最后的换行符?这是VB在读多行文件时出现的问题,最后行多了换行字符。可以用Left函数来取去除最后换行字符的文本。Left函数返回Variant(String),其中包 ... [详细]
  • 场景:1.比如在界面开发中,多个窗口之间需要通讯,比较常见的方法就是各个窗口之间包含对其他窗口的引用,之后在需要时通过其他窗口的引用来调用相应的函数获取相应的值;但是这个确 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 解决IDEA配置xml文件头报错的方法
    本文介绍了解决IDEA配置xml文件头报错的方法,包括了具体的解决方案和步骤。通过本文的指导,读者可以轻松解决这个问题并正常使用IDEA进行开发工作。 ... [详细]
  • 本文介绍了iOS开发中检测和解决内存泄漏的方法,包括静态分析、使用instruments检查内存泄漏以及代码测试等。同时还介绍了最能挣钱的行业,包括互联网行业、娱乐行业、教育行业、智能行业和老年服务行业,并提供了选行业的技巧。 ... [详细]
  • 九、删除用户 并提交代码到git仓库
    (1)弹框询问用户是否删除数据 ... [详细]
  • 代码逻辑:拷贝功能:1.从编辑控件中获取文本。2.打开并清空剪贴板。(OpenClipboard,EmptyClipboard)3.创建一个全局缓冲区。(GlobalAlloc)4 ... [详细]
  • 使用HTML创建弹出框以便用户输入信息
    在做项目的过程中,我们时常需要进行一些弹框操作,比如在后台管理时需要进行的一些增删改操作,这个时候我们需要使用到弹框,或者在 ... [详细]
  • 逆向工具之unidbg(在pc端模拟执行so文件中的函数)
      昨天在逆向某App的时候,发现有个加密工具类中的native方法是用C语言编写的,隐藏在so文件中。某大佬推荐逆向工具unidbg,能在pc端直接调用so文件中的函数,最终成功 ... [详细]
  • 转载自http:blog.csdn.netzhifeiyu2008articledetails8829637打开Java的JAR文件我们经常可以看到文件中包含着一个META-INF ... [详细]
  • Chapter4:菜单FileSettingsAppearanceBehavior
    本教程使用社区版IntelliJIDEA2021.1。1SettingsIDEA配置功能列表如图1.1所示。图1.1Settings功能预览由图1.1可知,配置列 ... [详细]
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社区 版权所有