上篇博客(WmS具体解释(一)之token究竟是什么?基于Android7.0源代码)中我们简要介绍了token的作用,这里涉及到的概念非常多,当中出现频率最高的要数Window和窗体这一对搭档了,那么我们今天就来看看究竟我们该怎样理解Android系统中的Window和窗体。

窗体这个概念。从不同的角度来看它的含义不一样。如果我们从WmS(WindowManagerService)的角度来看窗体。那么这个窗体并非一个Window类。而是一个View。用户发来的消息被WmS接收之后并不能直接发给各个View,真正接收用户消息的是IWindow类,IWindow类的实现类是ViewRootImpl.W类,每个W类内部都有一个View变量,WmS在收到用户发来的消息之后,推断哪一个窗体处于活动状态,找到之后将用户消息交给W类,W类再把用户消息传递给内部的View变量,剩下的事情就是View对象来搞定了。总的来说,在WmS眼中。窗体就是一个View。本文后面提到窗体都是指一个View;Window则是对窗体行为的进一步提取和抽象,Window将窗体的一些公共行为抽取出来统一处理。相当于Window是窗体的一个子集。

OK。说完了窗体的定义。接下来我们来看看窗体的类型。

窗体分类

依据窗体的type属性。窗体能够分为三大类。各自是应用窗体、子窗体和系统窗体。View的加入都是通过WindowManagerImpl类中的addView方法来实现的,该方法终于调用了WindowManagerGlobal中的addView方法,我们来看看这种方法:

public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
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 this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
} root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
} ......
...... }

该方法接收四个參数,第一个參数表示要加入的View,第二个參数表示该View的參数,第三个參数表示要输出的显示设备,第四个參数表示该View的父布局。当中第二个參数params要求必须是WindowManager.LayoutParams的实例。这个參数params中有一个參数type就是用来标记每个窗体的类型。这个类型实际上是一个int值。这个int值表示窗体的层,WmS在进行窗体叠加的时候,依照int常量大小分配不同的层。int值越大。View越靠近上层,int值越小,View越靠近下层。接下我们就来具体看一看这三种不同的窗体类型:

应用窗体

Activity相应的窗体就是应用窗体。可是由于Activity的载入是由AmS来完毕的,因此。应用窗体的创建实际上是由AmS来完毕的。

全部的Activity默认的窗体类型都是TYPE_APPLICATION,这个从WindowManager.LayoutParams的构造方法中就能够看出:

public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}

这一类中,系统提前定义了几个变量。我们来看一下:

依据这张表小伙伴们能够发现,应用窗体的层值不会大于99。而系统在进行窗体叠加的时候会自己主动为窗体分配不同大小的层值。

子窗体

子窗体所以为子窗体是由于它有一个父窗体。父窗体能够是随意类型的其它窗体,我们在开发中常见的子窗体有PopupWindow、Dialog、ContextMenu、PopupMenu等。关于子窗体。系统也定义了几种类型,我们来看一下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

当我们创建子窗体时,我们能够指定窗体类型介于1000~1999之间,WmS在进行窗体叠加时。会动态调整层值。

系统窗体

常见的系统窗体有状态栏、导航栏(国内部分Android手机有)、发生ANR时的提示框、输入法窗体、Toast窗体、锁屏时显示的屏保以及各种管家自带的那种加速球。系统窗体不须要有相应的Activity窗体,它也不须要父窗体。大部分情况下我们见到的系统窗体都是由系统创建的,当然我们也能够自己来创建系统窗体,和另外两种类型的窗体一样。系统也帮我们创建了一部分系统窗体常量:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

其实,在Android7.0中,系统一共定义了三十多个系统窗体常量,可是有一部分眼下并没有使用,所以我这里就没有列出来。当我们创建系统窗体时,我们能够指定系统窗体的层值在2000-2999之间,WmS在进行窗体叠加时,会动态调整该层值,可是该值会介于2000-2999之间。

窗体创建

看了非常多理论知识,接下来我们来看看我们自己怎么样来创建窗体。

创建子窗体

如果我当前页面有一个Button,当我点击Button的时候。弹出一个子窗体,效果例如以下:

我们来看看代码:

    public void btnClick(View view) {
IBinder token = view.getWindowToken();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(200, 200, 0, 0, PixelFormat.TRANSPARENT);
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
lp.token = token;
final TextView tv = new TextView(this);
tv.setText("我是弹出子窗体");
tv.setBackgroundColor(Color.BLUE);
wm = getWindowManager();
tv.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
MainActivity.this.wm.removeView(tv);
}
return false;
}
});
this.wm.addView(tv, lp);
}

代码貌似没什么难度。这里我就不做过多解释了。

创建系统窗体

系统窗体可能是很多小伙伴使用较多的窗体创建方式,常见的360悬浮球就是用这样的方式实现的。这里我也举一个小样例:

    public void addView(View view) {
lp = new WindowManager.LayoutParams(80, 80, 0, 0, PixelFormat.TRANSPARENT);
lp.flags =
//Window不须要获取焦点。该属性会自己主动开启FLAG_NOT_TOUCH_MODAL
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
//当前window区域内的事件自己处理,区域外的事件交给底层的window处理
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
//锁屏状态下亦能显示window出来
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
lp.gravity = Gravity.LEFT | Gravity.TOP;
//注意參考点为ActionBar的左上角
lp.x = 200;
lp.y = 200;
//type用来描写叙述window的类型,window类型共分为三种:
//应用级Window(1-99)。子Window(1000-1999)。系统Window(2000-2999)
//层级大的Window会覆盖掉层级小的Window
lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
windowManager = getWindowManager();
windowManager.addView(tv, lp);
} public void removeView(View view) {
windowManager.removeView(tv);
}

这里两个方法,一个加入窗体,一个移除窗体。

可是使用系统窗体一般须要我们加入权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

OK,关于Window和窗体的介绍就说这么多吧,有问题欢迎留言讨论。

參考资料:

mod=viewthread&tid=555">1.浅析Android的窗体

以上。

WmS具体解释(二)之怎样理解Window和窗体的关系?基于Android7.0源代码的更多相关文章

  1. WmS详解(二)之如何理解Window和窗口的关系?基于Android7.0源码

    上篇博客(WmS详解(一)之token到底是什么?基于Android7.0源码)中我们简要介绍了token的作用,这里涉及到的概念非常多,其中出现频率最高的要数Window和窗口这一对搭档了,那么我们 ...

  2. WmS简介(三)之Activity窗口是如何创建的?基于Android7.0源码

    OK,在前面两篇博客中我们分别介绍了WmS中的token,同时也向小伙伴们区分了Window和窗口的区别,并且按照type值的不同将Android系统中的窗口分为了三大类,那么本篇博客我们就来看看应用 ...

  3. WmS详解(一)之token到底是什么?基于Android7.0源码

    做Android有些年头了,Framework层三大核心View系统,WmS.AmS最近在研究中,这三大块,每一块都够写一个小册子来介绍,其中View系统的介绍,我之前有一个系列的博客(不过由于时间原 ...

  4. openssl之EVP系列之5---EVP_Encrypt系列函数具体解释(二)

    openssl之EVP系列之5---EVP_Encrypt系列函数详细解释(二)    ---依据openssl doc/crypto/EVP_EncryptInit.pod和doc/ssleay.t ...

  5. SQL Server Window Function 窗体函数读书笔记二 - A Detailed Look at Window Functions

    这一章主要是介绍 窗体中的 Aggregate 函数, Rank 函数, Distribution 函数以及 Offset 函数. Window Aggregate 函数 Window Aggrega ...

  6. Android开发艺术探索》读书笔记 (8) 第8章 理解Window和WindowManager

    第8章 理解Window和WindowManager 8.1 Window和WindowManager (1)Window是抽象类,具体实现是PhoneWindow,通过WindowManager就可 ...

  7. Android 布局学习之——Layout(布局)具体解释二(常见布局和布局參数)

     [Android布局学习系列]   1.Android 布局学习之--Layout(布局)具体解释一   2.Android 布局学习之--Layout(布局)具体解释二(常见布局和布局參数)   ...

  8. 理解Window和WindowManager

    Window表示一个窗口的概念,Window是一个抽象类,它的具体实现是PhoneWindow.创建一个Window,需要通过WindowManager即可完成,WindowManager是外界访问W ...

  9. ElasticSearch评分分析 explian 解释和一些查询理解

    ElasticSearch评分分析 explian 解释和一些查询理解 按照es-ik分析器安装了ik分词器.创建索引:PUT /index_ik_test.索引包含2个字段:content和nick ...

随机推荐

  1. python 搭建ftp服务器

    代码示例: # coding: utf-8 import os from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.han ...

  2. AliSQL 5.6.32 vs MySQL 5.7.15抢鲜测试

    摘要:    今天我们有幸抢鲜测试AliSQL,直接拿来和MySQL 5.7.15对比看看. AliSQL刚宣布开源,我就提交申请内测名额,节前收到开放内测邀请,于是第一时间进行了测试了解,希望能给大 ...

  3. ios处理键盘

    #pragma mark - Keyboard - (void)addKeyboardNoti { [[NSNotificationCenter defaultCenter] addObserver: ...

  4. php实现文件下载代码一例

    php实现文件下载代码 需要用到header函数来发送相关信息给客户端浏览器,同时再结合filesize函数来读取文件大小并进行下载操作.简单的文件下载只需要使用HTML的连接标记<a>, ...

  5. django——文件上传_分页_ajax_富文本_celery

    上传文件 概述 当Django在处理文件上传时,文件的数据被存储在request.FILES属性中 FILES只有在请求的方法为POST且提交的form表单带有enctype="multip ...

  6. C++11 强枚举类型

    在标准C++11之前的枚举是继承C的,枚举类型不是类型安全的.枚举类型被视为整数,这使得两种不同的枚举类型之间可以进行比较. 一.C中enum类型的局限语法: enum type1{a, b, c}; ...

  7. 【Java Concurrency】sleep()、wait()、notify()、notifyAll()的用法与区别

    >关于本文 本文介绍sleep().wait().notify().notifyAll()方法,主要要理解: sleep()和wait()的区别. wait()与notify().notifyA ...

  8. 解决kafka集群由于默认的__consumer_offsets这个topic的默认的副本数为1而存在的单点故障问题

    抛出问题: __consumer_offsets这个topic是由kafka自动创建的,默认50个,但是都存在一台kafka服务器上,这是不是就存在很明显的单点故障?经测试,如果将存储consumer ...

  9. js获取系统的根路径实现介绍

    js如何获取系统的根路径,在本文给出了详细的方法 function getBasePath(){ var obj=window.location; var contextPath=obj.pathna ...

  10. Python(四)之Python流程控制(if、while、for)

    Python流程控制 if测试: if 条件测试表达式: 组合条件测试: x and y:与运算 x or y:或运算 not x:非运算 while: break:跳出最内层的循环 continue ...