android开发艺术(六)之 Window

1. Window简介

Window表示窗口概念,在桌面显示类似悬浮窗效果,Android中所有的视图都是通过Window来呈现的
WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。

2. Window&windowManager

2.1 Window&PhoneWindow

  • Window是一个抽象类,提供了各种窗口操作的方法,比如设置背景标题ContentView等等
  • PhoneWindow则是Window的唯一实现类,它里面实现了各种添加背景主题ContentView的方法,内部通过DecorView来添加顶级视图
  • 每一个Activity上面都有一个Window,可以通过getWindow获取

2.2 Window&View

每个Window都对应一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。Window并不可见,它实际以View的形式存在,它是View的直接管理者

2.3 Window&WindowManager:

实际使用中无法访问Window,对Window的访问必须通过WindowManager,对Window的操作通过它完成。
实例:Windowmanager添加window:(将一个button添加到屏幕(100,300)坐标上)
开启权限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
在这里插入图片描述
在这里插入图片描述
WindowManager的三个参数:
1.flags:表示Window的属性。主要的可选值含义:

  • FLAG_NOT_FOCUSABLE:表示Window不需要获取焦点,也不需要接收各种输入事件,此标记会同时启动FLAG_NOT_TOUCH_MODEL,最终事件会传递给下层的具有焦点的Window。
  • FLAG_NOT_TOUCH_MODAL:表示系统会将当前Window区域以外的单击事件传递给底层的Window,而区域以内的单击事件则自己处理。一般都需要开启此标记,否则其他Window将无法收到单击事件。
  • FLAG_SHOW_WHEN_LOCKED:表示Window可显示在锁屏界面。

2.type:表示Window的类型。Window有三种类型:

  • Applicationwindows:
    层级取值在 FIRST_APPLICATION_WINDOW 和 LAST_APPLICATION_WINDOW 之间(0-99)
    是通常的、顶层的应用程序窗口。必须将 token 设置成 activity 的 token 。
  • Sub_windows:
    层级取值在 FIRST_SUB_WINDOW 和 LAST_SUB_WINDOW 之间(1000-1999)
    与顶层窗口相关联,token 必须设置为它所附着的宿主窗口的 token。
  • Systemwindows:
    层级取值在 FIRST_SYSTEM_WINDOW 和 LAST_SYSTEM_WINDOW 之间(2000-2999)
    用于特定的系统功能。它不能用于应用程序,使用时需要特殊权限。

如果想要Window位于所有Window的最顶层,那么采用较大的层级即可。系统Window的层级是最大的,系统层级有很多值, 系统层级取值一般选用:TYPE_SYSTEM_OVERLAYTYPE_SYSTEM_ERROR
方法:layoutParams.type=LayoutParams. TYPE_SYSTEM_ERROR
同时必须开启权限:“android.permission.SYSTEM_ALERT_WINDOW”

3.gravity:表示Window的位置。默认是屏幕中间。x、y值相对于gravity。

2.4 .WindowManager&WindowManagerService:

Window的具体实现位于WindowManagerService中。WindowManager和WindowManagerService的交互是一个IPC(跨进程通信)过程。

3.Window的内部机制

1.WindowManager所提供的功能很简单,常用的只有三个方法,即添加View,更新View和删除View,这三个方法定义在ViewManager中,而WindowManager也是一个接口,它继承了ViewManager接口.

public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);//添加过程
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);//更新过程
    public void removeView(View view);//删除过程
}

对window进行操作实际上就是对view进行操作,举例实现window的拖动效果:

floatbutton.setOnTouchListener(this);
然后对onTouch函数进行重写操作

2.每一个window对应着一个view和一个viewRootImpl。Window和view通过viewRootImpl建立联系
WindowManager是一个接口,真正实现是WindowManagerImpl类

public final class WindowManagerImpl implements WindowManager{
        @Override
        public void addView(View view, ViewGroup.LayoutParams params){
            mGlobal.addView(view, params, mDisplay, mParentWindow);
        }
        
        @Override
        public void updateViewLayout(View view, ViewGroup.LayoutParams params){
            mGlobal.updateViewLayout(view, params);
        }
        
        @Override
        public void removeView(View view){
            mGlobal.removeView(view, false);
        }
}

该类没有直接实现三大操作,而是交给WindowManagerGlobal处理,后者以工厂的形式向外提供自己的实例:Private final WindowManagerGlobal mGlobal=WindowManagerGlobal.getInstance();
在这里插入图片描述
通过WindowManagerGlobal的addView()、updateViewLayout()、removeView()实现WindowManager对Window的添加、删除和修改

  • WindowManagerGlobal的addView:
  1. 检查参数是否合法,如果是子window还需调整布局参数
  2. 创建ViewRootImpl实例 并将View添加到列表中
  3. 通过ViewRootImpl的setView—requestLayout—scheduleTraversals—view绘制,来更新界面,最后通过WindowSession–WindowManagerService完成Window的添加过程
  • WindowManagerGlobal的removeView()
    removeViewLocked—通过ViewRootImpl完成删除操作,其中window提供两种删除接口,RemoteView和RemoveViewImmediate,表示异步删除和同步删除—使用ViewRootImpl的die方法发送请求删除的消息—ViewRootImpl的Handler处理异步删除的消息并调用doDie—doDie中调用真正执行删除逻辑的dispatchDetachedFormWindow,它主要完成:
    (1)垃圾回收相关的工作,比如清除数据和消息、移除回调。
    (2)通过Session的remove方法删除Window: mWindowSession remove(mWindow), 这是一个IPC过程,最终会调用WindowManagerService的removeWindow方法。
    (3)调用View的dispatchDetachedFromWindow方法,在内部会调用View的onDetachedFromWindow(以及onDetachedFromWindowIntermalO。当View从Window中移除时,这个方法就会被调用,可以在这个方法内部做一些资源回收的工作,比如终止动画、停止线程等。
    (4)调用WindowManagerGlobal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews,需要将当前Window所关联的这三类对象从列表中删除。
  • WindowManagerGlobal的updateViewL ayout
    首先它需要更新View的LayoutParams替换掉老的LayoutParams,接着再更新ViewRootlmpl中的LayoutParams,这一步是通过ViewRootlmpl的setIayoutParams方法来实现的。在ViewRootmpl中会通过scheduleTraversals方法来对View重新布局,包括测量、布局、重绘这三个过程。除了View本身的重绘以外,ViewRootlmpl 还会通过WindowSession 来更新Window 的视图,这个过程最终是由WindowManagerService的relayoutWindow()来具体实现的,它同样是一个IPC过程。

4.Window的创建过程

View必须依附Window才能呈现出来,因此有View的地方必有Window。在Android中可以提供View的地方有Activity、Dialog和Toast

  1. Activity的Window创建
    首先由ActvityThread.performLaunchActivity完成活动的启动工作,接着实现window的创建,然后由setContentView完成布局的加载—交给window的setContentView处理—window的具体实现是phoneWindow,由phoneWindow的setContentWindow完成—1.如果没有DecorView就创建一个,通过generateLayout加载具体的布局文件到DecorView 2.将View添加到DecorView的mContentParent 3.回调Activity的onContentChanged通知Activity视图已经发生改变—Activity的makeVisible方法呈现Activity视图
  2. Dialog的Window创建过程
    Step1:创建WindowDialog。和Activity类似,同样是通过PolicyManager.makeNewWindow()来实现。
    Step2:初始化DecorView并将Dialog的视图添加到DecorView中去。和Activity类似,同样是通过Window.setContentView()来实现。
    Step3:将DecorView添加到Window中显示。和Activity一样,都是在自身要出现在前台时才会将添加Window。
    Dialog.show()方法:完成DecorView的显示。
    WindowManager.remoteViewImmediate()方法:当Dialog被dismiss时移除DecorView。
    普通的 Dialog有一个特殊之处,那就是必须采用Activity的Context,如果采用Application的Context, 那么就会报错。
  3. Toast的Window创建过程
    ①Toast的内部的视图由两种方式指定:
    系统默认的样式;通过setView()指定一个自定义View。
    ②Toast具有定时取消功能,故系统采用Handler做定时处理。
    ③在Toast内部有两类IPC过程:
    Toast访问NotificationManagerService(NMS);
    NotificationManagerService回调Toast里的TN接口。
    ④Toast提供方法show()和cancel()分别用于显示和隐藏Toast。
  • Toast的显示和隐藏都需要通过NMS来实现,由于NMS运行在系统进程中,故需通过远程调用的方式来进行显示和隐藏Toast。
  • NMS处理Toast的显示和隐藏请求时会跨进程回调TN中的方法,由于TN运行在Binder线程池中,故需通过Handler将其切换到当前线程(发送Toast请求的线程)。
  • NMS只是起到了管理Toast队列及其延时的效果,Toast 的显示和隐藏实际是通过TN来实现的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值