一、Window简介

作用:桌面上显示一个类似悬浮的东西。

介绍:Window是一个抽象类,实现是由PhoneWindow。WindowManager是外界访问Window的入口。但是最终实现是在WindowService中。WindowManger和WindowService是IPC交互。Andorid所有的视图都是由Window实现的,所以Window是View的直接管理者。(从第四章也知道)

二、Window和WindowManager

(一)、如何添加一个Window到WindowManager

步骤:①、在java代码中创建一个View ②、创建View对应的LayoutParams属性 ③、结合View与Layout放入WindowManager.addView()中。

//创建View
TextView float = new TextView(context);
float.settext("this is a float window ");
//创建LayoutParams
WindowManager.LayoutParams params = new LayoutParams();
//配置LayoutParams
params.width = width;
params.height = height;
params.format = PixelFormat.TRANSLUCENT;
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;//后面窗口仍然可以处理点设备事件
params.setTitle("Toast");
params.gravity = gravity;
params.windowAnimations = styleAnimations;
//获取WindowManager
WindowManager windowManager =
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
//将Window添加到WindowManager
windowManager.addView(view, this.mLayoutParams);

两个重要的设置参数:flags和type

常见flags:

FLAG_NOT_FOCUSABLE:不需要获取焦点,不接受各种输入事件(同时启用FLAG_NOT_TOUCH_MODAL)。最终事件传给下层具有焦点的Window

FLAG_NOT_TOUCH_MADAL:系统将当前Window区域以外的单击事件传给下一层Window,当前Window区域内的单击事件则自己处理。

FLAG_SHOW_WHEN_LOCKED:让Window显示在锁屏界面上

常见Type(表示Window的类型):

应用类Window:对应着一个Activity

子Window:无法单独存在,需要附属在特定的父Window上(比如:Dialog就是子Window)。

系统Window:需要声明权限在创建(Toast,系统状态栏都是)

Window的分层概念:应用Window1~99层,子Window1000~1999层,系统Window2000~2999(同时系统层级有许多值,一般采用TYPE_SYSTEM_OVERLAY,并声明权限P296)

WindowManager.Params 中的Gravity的作用:

Gravity:表示params.x和params.y 相对于Gravitiy的偏移量。

比如说:

parmas.gravity = Gravity.LEFT|Gravity.TOP;

表示x相对于左边的偏移量,y相对于右边的偏移量

WindowManger方法及Window的拖动效果

主要方法(继承了ViewManger):

public interface ViewManager{
//添加View
public void addView();
//升级View的Layout
public void updateViewLayout();
//移除View
public void removeVIew();
}
//详细参数将P296

Window的拖动效果

public void onTouch(View v,MontionEvent event){
//获取当前绝对位置
int rawX= (int)event.getRawX();
int rawY = (int)event.getRawY();
//当移动的时候,将位置给Layout,然后从新载入layotu
switch(event.geAction){
case MotionEvent.ACTION_MOVE:
mLayoutParams.x = rawX;
mLayoutParans.y = rawY;
mWindowManger.updateViewLayout(view,mLayoutParams);
break;
}
}

三、Window的内部机制

window的定义:window是一个抽象概念,每个Window都对应着一个View和ViewRootImpl。Window与View通过ViewRootImpl建立联系。WindowManager的所有方法都是针对View的,所以View才是Window的实现。

分析Window的增、删、改

从addView开始:WindowManger只是一个接口,WindowMangerIml才是接口的实现类,根据内部方法,交给WindowMangerGlobal类来处理。

WindowManagerGlobal  :首先检查参数是否合法

之后创建ViewRootImpl并将分别放入两个ArrayList中(详见P299 2)。

通过ViewRootIml的setView()方法调用内部requestLayout()调用scheduleTraversals()然后利用mWindowSession(是Binder对象).appToDisplay(所以整个实现通过了一层IPC),真正实现类是Session类。在Session类中,通过WindowMangerService实现Window添加。

Window的删除过程:

调用WindowManager的removeView()方法,同样交给WindowMangerGlobal处理(源码P301 ①):寻找该View的index,之后通过removeViewLocked()进一步删除。

根据removeViewLocked()源码(P301 ②):是通过ViewRootImpl进行删除的,其中会调用root.die()方法。WindowManager提供两种删除接口removeView(异步删除:不会立刻删除)removeViewImmidate(同步删除:立刻删除)。如果是同步删除的话,就加入WindowManager的mDyingViews的View列表中。

查看die方法(源码P302 ①):当判断为异步删除的话,就会向ViewRootImpl的Handler发送MSG_DIE的消息,之后等待Handler处理消息,调用doDie()方法。如果为同步删除则直接调用doDie()方法。

真正删除View的逻辑是在dispatchDetachedFormWindow方法,其主要逻辑是:

1.垃圾回收相关工作

2.通过Session的remove方法移除Window:最终调用WindowManagerService的removeWindow()方法

3.调用View的dispathDetachedFromWindow方法,内部调用View的onDetachedFormWindow()。可以在onDetachedFromWindow()方法中做些回收资源的工作,如终止动画、停止线程。

4.调用WindowManagerGlobal的doRemoveView方法刷新数据包。

Window的更新过程:

更新View的LayoutParams,之后得到该View对应的ViewRootImpl,并调用viewRoot的setLayoutParams()实现更新。

在setLayoutParams()中,会调用ScheduleTraversals()方式实现,测量、布局、重绘这三个过程。之后通过WindowSession更新视图,发送给WindowManagerService。

四、Window的创建过程

(一)、Activity的Window创建过程

最终由AcitivityThread中的perfirmLauchActivity()完成整个启动过程(源码:P305 ①)

作用:①、配置上下文环境变量  ②、调用Activity的attach()方法 。

attach()方法:

作用:创建Window对象,并为其设置Callback回调(例如:onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent)。

创建Window对象使用PolicyManager的工厂方法。

PolicyManager:是一个策略类,且继承IPolicy接口(工厂方法都在该接口声明  P306  ①)。所以真正实现是在Policy类中,调用Policy的makeNewWindow()方法(P306 ②),发现创建PhoneWindow对象,说明window的具体实现是PhoneWindow。

(二)、Activity是如何附属在Window上的

根据Activity的setContentView()(P306 ③):

作用:Activity将具体实现交给Window处理。运用PhoenWindow.setContentView()方法

根据PhoenWindow.setContentView()的方法:

作用:①、若没有DecorView则创建,内部方法会调用generateDecor()方法(P307 ①)。  ②、之后通过generateLayout来加载布局文件(P307 ②)(第四章讲过DecoreView的布局)并将DecoreView的content布局设置为contentParent布局,所有Acitivity的视图都在其中。

③Acitivity的视图添加到DecorView的mContentParent中就可以了:mLayoutInflater.inflate(layoutResID,mContentParent)。这就完成了将Activity布局放入到DecorView的过程。

④、当Activity的布局文件添加到DecoreView中的时候就会通知Activity(Activity实现了Window的CallBack()方法)视图改变,调用onContentChanged()方法(该方法是个空实现,可以在自己的Activity实现该方法)

到此为止DecorView还没有从WindowManager添加到Window中。

⑤、在ActivityThread的handleResumeActivity方法中,调用Activity的onResume()方法,接着调用Activity的makeVisible(),在此方法中才真正完成了添加和显示(P308 ①)

(三)、Dialog的Window创建过程

步骤:①、通过setContentView(P309 ①)调用PhoneWindow的setContentView();  ②、通过PhoneWindow的setContentView()(P309 ②)初始化DecorView并将Dialog视图添加到DecorView中   ③、通过Dialog的show()方法(P309 叁③),将DecorView添加到Window中。

注:普通的Dialog有一个特殊之处,必须采用Activity的Context,不能采用Application的Context。(解决办法 P310)

(四)、Toast的Window的创建

前提:Toast有定时取消这个功能,所以系统采用了Handler。

简单原理:Toast访问NotificationManagerService,然后通过NotificationManagerService回调Toast中的TN的接口(实现了Binder,类似在AIDL中实现观察者模式)。

①、Toast属于Window,指定视图的方式:一种采用默认样式,第二种通过setView指定自定义View。Toast提供了show()和cancel方法(P311 ①),内部是一个IPC过程。

②、当实现show()和cancel()的时候,NotificationService会回调TN接口,因为该接口是在Binder线程池运行的,所以需要Handler将其切换到当前线程。因为需要Handler所以Toast不能运行在没有Looper的线程中。

③、显示过程(P312 ①)调用了NMS的enqueueToast():参数1是包名,参数2是TN回调接口,参数3是持续时间。

作用:首先将Toast请求封装成ToastRecord对对象,装入mToastQuene队列中去。

④、之后NMS调用shiwNextToastLocked()显示当前Toast,通过调用ToastRecord的TN回调(P313 ①)。

⑤、TN回调之后NMS还会调用sheculeTimeoutLocked()(P314 ①):

作用:发送延时消息(取决于Toast的时间),当达到时间后,NMS会调用cancelToastLocked()隐藏Toast,并将其从mToastQueue中删除。

⑥、分析TN回调(P315 ①):通过Handler将操作从Binder中转换到本地,当Handler接收到消息的时候,如果是show()则(P315 ②)利用WinowManager的addView()添加视图,如果是hide()则(P315 ③)调用WindowManager的removeView()方法。

理解Window和WindowManger的更多相关文章

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

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

  2. 理解Window和WindowManager

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

  3. 【Android开发艺术探索】理解Window和WindowManager

    个人博客: http://www.milovetingting.cn 理解Window和WindowManager Window表示一个窗口的概念,是一个抽象类,具体实现是PhoneWindow,可以 ...

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

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

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

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

  6. 怎样理解window对象的几组位置大小属性

    第一组: window.screenX 和 window.screenY, 只读, 返回浏览器窗口左上角与屏幕左上角的水平距离和垂直距离(单位像素); 第二组: window.innerHeight ...

  7. 怎样理解window.name

    window.name表示当前窗口的名字, 而非网页的名字, 网页的名字需要使用: document.title; window.name一般是空的字符串, 他的作用其实是配合配合超链接和表单的tar ...

  8. 第八章:理解Window和WindowManager

    Window表示一个窗口的概念. Window是一个抽象类,它的具体实现是PhoneWindow, WindowManager是外界访问Window的入口,Window的具体实现位于WindowMan ...

  9. Android GUI之Window、WindowManager

    通过前几篇的文章(查看系列文章:http://www.cnblogs.com/jerehedu/p/4607599.html#gui ),我们清楚了Activity实际上是将视图的创建和显示交给了Wi ...

随机推荐

  1. 逛园子,看到个练习题,小试了一把(淘宝ued的两道小题)

    闲来无事,逛园子,充充电.发现了一个挺有意思的博文,自己玩了一把. 第一题:使用 HTML+CSS 实现如图布局,border-widht 1px,一个格子大小是 60*60,hover时候边框变为橘 ...

  2. 如何使用Assetic进行文件管理

    安装和配置Assetic 从symfony2.8开始,Assetic就不再被包括在symfony标准版.使用任何Assetic的特性之前需要安装AsseticBundel,在命令行执行下面命令: $ ...

  3. 检测.net framework 版本

    项目中,自己要制作asp.net项目的安装文件,由于项目依赖于.net framework 3.5 sp1,故需检测环境是否符合要求,才能安装程序 度娘找到检测方案:各.net版本对应的安装补录下都有 ...

  4. [statsvn]-svn代码量统计

    用statasvn进行代码量统计的时候,第一步需要获取到项目的日志,但是我本机的svn1.4没有安装命令行,重新运行1.4的安装包也没有命令行的选项... 那就升级到最新的svn1.8好了,下载最新的 ...

  5. BZOJ NOI十连测 第二测 T2

    思路:20%可以搜索.. #include<algorithm> #include<cstdio> #include<cmath> #include<cstr ...

  6. 【转】【漫画解读】HDFS存储原理

    根据Maneesh Varshney的漫画改编,以简洁易懂的漫画形式讲解HDFS存储机制与运行原理. 一.角色出演 如上图所示,HDFS存储相关角色与功能如下: Client:客户端,系统使用者,调用 ...

  7. PHP MySQL 连接数据库 之 Connect

    连接到一个 MySQL 数据库 在您能够访问并处理数据库中的数据之前,您必须创建到达数据库的连接. 在 PHP 中,这个任务通过 mysql_connect() 函数完成. 语法 mysql_conn ...

  8. Python3.X与Python2.x的区别

    一张图说明Python2.x与Python3.x的不同. Python3.x默认使用Unicode编码.支持中文. 更多介绍请看:https://segmentfault.com/a/11900000 ...

  9. Unity 使用实体类

    故事的由来: 正在开发打飞机的游戏,遇到这样的数据结构,游戏有很多关卡-> 每个关卡有几波怪物->每一波里面有怪物和数量 [] 关卡 { []波{ {怪物,数量},{怪物,数量},{怪物, ...

  10. hdu 4611

    2013hdu多校联赛二的第一题,当时队友说两个盒子个数的最小公倍数是周期, 如果两个数的最小公倍数比较大的时候(最大是9999900000),如果遍历求的话肯定会超时 当时想找各种规律,都没找到,最 ...