《android开发艺术探索》读书笔记(八)--WindowManager

No1:

Window是一个抽象类,它的具体实现是PhoneWindow。创建一个Window是很简单的事,只需要通过WindowManager即可完成。

WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindwoManager和WindowManagerService的交互时一个IPC过程。

Android中所有的视图都是通过Window来呈现的,因此Window实际是View的直接管理者。

单机事件由Window传递给DecorView,然后再由DecorView传递给我们的View。

No2:

Window有三种类型,分别是应用Window、子Window和系统Window。

应用Window--一个Activity

子Window--不能单独存在,需要附属在特定的父Window中,比如Dialog

系统Window--是需要声明权限才能创建的Window,比如Toast和系统状态栏

No3:

Window是分层的,每个Window都有对应的z-ordered,层级大的会覆盖在层级小的Window的上面。

应用层Window层级范围1~99

子Window层级范围1000~1999

系统Window层级范围2000~2999

这些层级范围对应着WindowManager.LayoutParams的type参数。如果想要Window位于所有Window的最顶层,那么采用较大的层级即可。

No4:

WindowManager所提供的功能很简单,常用的只有三个方法,添加ViewaddView、更新ViewupdateViewLayout和删除ViewremoveView,这三个方法定义在ViewManager中,而WindowManager继承了ViewManager。

No5:

可以拖动的Window效果

public boolean onTouch(View v,MotionEvent event){
    int rawX = (int)event.getRawX();
    int rawY = (int)event.getRawY();
    switch(event.getAction()){
        case MotionEvent.ACTION_MOVE:
            mLayoutParams.x = rawX;
            mLayoutParams.y = rawY;
            mWindowManager.updateViewLayout(mFloationButton,mLayoutParams);
            break;
        default:
            break;
    }
    return false;
}

No6:

Window是一个抽象的概念,每个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立连接,因此Window并不是实际存在的,它是以View的形式存在。

在实际使用中无法直接访问Window,对Window的访问必须通过WindowManager。

No7:

WindowManager是一个接口,它的真正实现是WindowManagerImpl类。WindowManagerImpl并没有直接实现Window的三大操作,而是全部交给了WindowManagerGlobal来处理。

WindowManagerImpl这种工作模式是典型的桥接模式。

No8:

Window的添加过程

1.检查参数是否合法,如果是子Window那么还需要调整一些布局参数

2.创建ViewRootImpl并将View添加到列表中

3.通过ViewRootImpl来更新界面并完成Window的添加过程

View的绘制过程是由ViewRootImpl来完成的,在setView内部会通过requestLayout完成异步刷新请求,scheduleTraversals实际是View绘制的入口,接着会通过WindowSession最终来完成Window的添加过程,真正的实现类是Session,也就是Window的添加过程是一次IPC调用,在Session内部会调用WindowManagerService来实现Window的添加。

No9:

Window的删除过程

WindowManagerImpl-->WindowManagerGlobal-->ViewRootImpl

WindowManager中提供了两种删除接口removeView和removeViewImmediate,分别表示异步删除和同步删除。

异步删除具体的删除操作由ViewRootImpl的die方法来完成,die发送了一个请求删除的消息,ViewRootImpl中的Handler会处理此消息并调用doDie方法,如果是同步删除,那么就不发消息直接调用doDie方法。

doDie内部会调用dispatchDetachedFromWindow方法,dispatchDetachedFromWindow主要做四件事:

1)垃圾回收相关工作,比如清除数据和消息、移除回调

2)通过Session的remove方法删除Window:mWindowSession.remove(mWindow),这同样是一个IPC过程,最终会调用WindowManagerService的removeWindow方法

3)调用View的dispatchDetachedFromWindow方法,在内部会调用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。

当View从Window中移除时,这个方法就会被调用,可以在这个方法内部做一些资源回收的工作,比如终止动画、停止线程等

4)调用WindowManagerGolbal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews,需要将当前Window所关联的这三类对象从列表中删除。

No10:

Window的更新过程:还是要看WindowManagerGlobal的updateViewLayout方法:

1)通过ViewRootImpl的setLayoutParams更新View的LayoutParams并替换掉老的LayoutParams,接着再更新ViewRootImpl中的LayoutParams

2)在ViewRootImpl中会通过scheduleTraversals方法来对View重新布局,包括测量、布局、重绘这三个过程

3)ViewRootImpl还会通过WindowSession来更新Window视图,最终是由WindowManagerService的relayoutWindow()来具体实现的。同样是一个IPC过程

No11:

Window对象的创建是通过PolicyManager的makeNewWindow方法实现的。PolicyManager的真正实现是Policy类,所以Window的具体实现的确是PhoneWindow。

No12:

setContentView:Activity-->Window-->PhoneWindow

No13:

DecorView是一个FrameLayout,是Activity中的顶级View,一般包括标题栏和内部栏

No14:

Activity的Window的创建过程

PhoneWindow的setContentView步骤

1)如果没有DecorView,那么就创建它

2)将View添加到DecorView的mContentParent中(这就是为Activity的setContentView而不叫setView的缘由

3)回调Activity的onContentChanged方法通知Activity视图已经发生改变

No15:

在ActivityThread的makeVisible()方法中,首先会调用Activity的onResume方法,接着会调用Activity的makeVisible(),正是在makeVisible方法中,DecorView真正地完成了添加和显示这两个过程,到这里Activity的视图才能被用户看到。

No16:

Dialog的Window创建过程

1)创建Window

2)初始化DecorView并将Dialog的视图添加到DecorView中

3)将DecorView添加到Window中并显示

No17:

普通Dialog有一个特殊之处,就是必须采用Activity的Context,如果采用Application的Context,会报错没有token,而应用token一般只有Activity拥有。

系统Window不需要token,因此只要指定对话框为Window为系统类型即可

No18:

Toast具有定时取消这一功能,所以系统采用了Handler。

Toast内部有两类IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast里面的TN接口。

显示和隐藏Toast都需要通过NotificationManagerService来实现,因为NMS运行在系统进程中,所以只能通过远程调用的方式来显示和隐藏。TN是一个Binder类,它运行在Binder线程池中,所以需要Handler将其切换到当前线程中,这里的当前线程是指发送Toast请求所在的线程。

No19:

enqueueToast首先将Toast请求封装为ToastRecord对象并将其添加到一个名为mToastQueue的队列中。mToastQueue其实是一个ArrayList。对于非系统应用来说,mToastQueue中最多能同时存在50个ToastRecord。如果不这样做,将导致其他引用没有机会弹出Toast。

No20:

Toast延时相应时间后,NotificationManagerService会通过cancelToastlocked方法来隐藏Toast并将其从mToastQueue中移除,这个时候如果mToastQueue中还有其他Toast,那么NMS就继续显示其他Toast。Toast的隐藏也是通过ToastRecord的callback来完成的,这同样也是一次IPC过程。

No21:

Toast中TN的两个方法show和hide,是以NMS以跨进程的方式调用的,因此它们运行在Binder线程池中。

原文地址:https://www.cnblogs.com/anni-qianqian/p/8287526.html

时间: 2024-08-11 16:48:55

《android开发艺术探索》读书笔记(八)--WindowManager的相关文章

Android开发艺术探索读书笔记——进程间通信

1. 多进程使用场景 1) 应用某些模块因为特殊需求需要运行在单独进程中.如消息推送,使消息推送进程与应用进程能单独存活,消息推送进程不会因为应用程序进程crash而受影响. 2) 为加大一个应用可使用的内存,需要多进程来获取多份内存空间. 2. 如何开启多进程 给四大组件(Activity.Service.Receiver.ContentProvider)在AndroidMainfest中指定android:process属性指定. 如果进程以":"开头的进程,代表应用的私有进程,其

android开发艺术探索读书笔记之-------view的事件分发机制

View的点击事件的分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生后,系统需要把这个事件传递给一个具体的View,而这个过程就是分发过程. 分发过程主要由以下3个方法共同完成: public boolean dispatchTouchEvent(MotionEvent event) 用来进行事件的分发.如果事件能够传递给当前的View,那么此方法一定会被调用,返回结果受当前的View的onTouchEvent和下级View的dispatchTouchEv

Android开发艺术探索(研读笔记)——03-Android中的IPC机制(一)

Android开发艺术探索(研读笔记) 作者:Dimon 微博:@Dimon-喰 GitHub:@Dimon94 LOFTER:@Dimon. 03-Android中的IPC机制(一) 1.Android IPC 简介 IPC(Inter-Process-Communication):含义为进程间通信,指两个进程之间进行数据交换的过程. 什么是进程:一般指一个执行单元,在PC和移动设备上的一个程序或者一个应用. 什么是线程:线程是CPU调度的最小单元,是一种有限的系统资源. 而一个进程可以包含多

Android动画(开发艺术探索读书笔记)

Android动画可以分为3类:View动画,帧动画,属性动画 1.View动画 可以通过XML来创建,也可以通过代码来创建 1.1通过XML创建 在res/anim下创建filename.xml文件,语法如下所示 <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" andro

Android开发艺术探索读书(三)-View的事件体系

移动手持客户端作为目前最受欢迎的智能设备,拥有着最为广大的体验用户群体.因此,作为软件开发商,要紧紧抓住用户的胃口,不仅要向用户提供合适的服务项目,也应该更为注重与用户的交互体验.而作为感觉型的用户,应用操作是否流畅,界面内容是不是足够精致,是判断该应用是不是一个好应用的硬性标准.那么,要如何去强化与用户的交互体验呢?这就涉及了本章所讲的内容:View的事件体系 提纲: 一.什么是View 二.View的位置参数 三.几个相关的View知识点 四.View的滑动深入 五.view的事件分发 六.

Android开发艺术探索学习笔记(十一)

第十一章  Android的线程和线程池 从用途上来说,线程分为子线程和主线程,主线程主要处理和界面相关的事情,而子线程往往用于执行耗时的操作.AsyncTask,IntentService,HandlerThread都可以扮演线程的角色. AsyncTask封装了线程池和Handler,主要是为了方便开发者在主线程中更新UI. HandlerThread是一种具有消息循环的线程,在它的内部可以使用Handler. IntentService是一个服务,系统对其进行了封装,使其可以更方便的执行后

《Android 开发艺术探索》笔记——(3)View 的事件体系

View 基础知识 View 是 Android 中所有控件的基类,ViewGroup 也继承了 View. Android 中,x 轴和 y 轴的正方向分别为右和下. 位置参数: (left , top ): View 左上角原始坐标 (right, bottom): View 右下角原始坐标 (x , y ): View 左上角最终坐标 translationX: View 左上角横向偏移量 translationY: View 左上角纵向偏移量 x = left + translation

《android开发艺术探索》读书笔记(五)--动画

接上篇<android开发艺术探索>读书笔记(五)--Drawable No1: 自定义动画:派生一种新动画只需要继承Animation这个抽象类,然后重写它的initialize和applyTransformation方法,在initialize方法中做一些初始化工作,在applyTransformation中进行相应的矩阵变换即可,很多时候需要采用Camera来简化矩阵变换的过程. No2: 属性动画PropertyAnimation 补间动画TweenAnimation 帧动画Frame

《android开发艺术探索》读书笔记(十三)--综合技术

接上篇<android开发艺术探索>读书笔记(十二)--Bitmap的加载和Cache No1: 使用CrashHandler来获取应用的crash信息 No2: 在Android中单个dex文件所能够包含的最大方法数为65536,这包含Android FrameWork.依赖的jar包以及应用本身的代码中的所有方法. No3: 使用multidex来解决方法数越界 apply plugin: 'com.android.application' android { compileSdkVers

《android开发艺术探索》读书笔记(十五)--Android性能优化

接上篇<android开发艺术探索>读书笔记(十四)--JNI和NDK编程 No1: 如果<include>制定了这个id属性,同时被包含的布局文件的根元素也制定了id属性,那么以<include>指定的id属性为准 No2: 绘制优化 1)onDraw中不要创建新的局部对象 2)onDraw方法中不要做耗时的任务 No3: 内存泄露优化 场景一:静态变量导致的内存泄露: 如果静态变量持有了一个Activity,会导致Activity无法及时释放. 解决办法:1使用Ap