Android进阶:深入理解Android窗口管理框架机制

移动开发 Android
通俗来说,Window就是手机上一块显示区域,也就是Android中的绘制画布Surface,添加一个Window的过程,也就是申请分配一块Surface的过程,而整个流程的管理者正是WindowManagerService。

[[423965]]

前言

WindowManagerService是位于Framework层的窗口管理服务,它的职责是管理系统中的所有窗口,也就是Window,关于Window的介绍,通俗来说,Window就是手机上一块显示区域,也就是Android中的绘制画布Surface,添加一个Window的过程,也就是申请分配一块Surface的过程,而整个流程的管理者正是WindowManagerService;

今天我们来分析下窗口WMS相关的知识点;

一、窗口相关概念

1、WindowManagerService概念

(1)WindowManagerService概念

Framework层的窗口管理服务,职责是管理Android系统中所有window。窗口管理服务,继承IWindowManager.Stub,Binder服务端,因此WM与WMS的交互也是一个IPC过程。WMS主要做的事情如下:

  • Z-ordered的维护函数
  • 输入法管理
  • AddWindow/RemoveWindow
  • Layerout
  • Token管理,AppToken
  • 活动窗口管理(FocusWindow)
  • 活动应用管理(FocusApp)
  • 转场动画
  • 系统消息收集线程
  • 系统消息分发线程

(2)WindowManager

应用与窗口管理服务WindowManagerService交互的接口;

(3)PhoneWindowManager

实现了窗口的各种策略,定义了窗口相关策略,比如:告诉WMS某一个类型Window的Z-Order的值是多少,帮助WMS矫正不合理的窗口属性,为WMS监听屏幕旋转的状态,预处理一些系统按键事件;

(4)Choreographer

用户控制窗口动画、屏幕选择等操作,它拥有从显示子系统获取Vsync同步事件的能力,从而可以在合适的时机通知渲染动作,避免在渲染的过程中因为发生屏幕重绘而导致的画面撕裂。WMS使用Choreographer负责驱动所有的窗口动画、屏幕旋转动画、墙纸动画的渲染;

(5)DisplayContent

用于描述多屏输出相关信息;

根据窗口的显示位置将其分组。隶属于同一个DisplayContent的窗口将会被显示在同一个屏幕中。每个DisplayContent都对应着唯一ID,在添加窗口的时候可以通过指定这个ID决定其将显示在哪个屏幕中;

DisplayContent是一个非常具有隔离性的一个概念。处于不同DisplayContent的两个窗口在布局、显示顺序以及动画处理上不会产生任何耦合;

(6)WindowState

描述窗口的状态信息以及和WindowManagerService进行通信,一般一个窗口对应一个WindowState。它用来表示一个窗口的所有属性;

(7)WindowToken

  • 窗口Token,用来做Binder通信;同时也是一种标识;
  • 在进行窗口Zorder排序时,属于同一个WindowToken的窗口会被安排在一起,而且在其中定义的一些属性将会影响所有属于此WindowToken的窗口,这些都表明了属于同一个WindowToken的窗口之间的紧密联系;
  • 应用组件在需要新的窗口时,必须提供WindowToken以表明自己的身份,并且窗口的类型必须与所持有的WindowToken的类型一致;
  • 在创建系统类型的窗口时不需要提供一个有效的Token,WMS会隐式地为其声明一个WindowToken,看起来谁都可以添加个系统级的窗口。难道Android为了内部使用方便而置安全于不顾吗?非也,addWindow()函数一开始的mPolicy.checkAddPermission()的目的就是如此。它要求客户端必须拥有SYSTEM_ALERT_WINDOW或INTERNAL_SYSTEM_WINDOW权限才能创建系;

(8)Session

App进程通过建立Session代理对象和Session对象通信,进而和WMS建立连接;

(9)SurfaceFlinger

SurfaceFlinger负责管理Android系统的帧缓冲区(Frame Buffer),Android设备的显示屏被抽象为一个帧缓冲区,而Android系统中的SurfaceFlinger服务就是通过向这个帧缓冲区写入内容来绘制应用程序中的用户界面的;

(10)InputManager

管理每个窗口的输入事件通道(InputChannel)以及向通道上派发事件;

(11)Animator

所有窗口动画的总管(WindowStateAnimator对象)。在Choreographer的驱动下,逐个渲染所有的动画;

2、Window

  • 表示一个窗口的概念,是所有View的直接管理者,任何视图都通过Window呈现(点击事件由Window->DecorView->View;Activity的setContentView底层通过Window完成)
  • Window是一个抽象类,具体实现是PhoneWindow;
  • 创建Window需要通过WindowManager创建;
  • WindowManager是外界访问Window的入口;
  • Window的具体实现位于WindowManagerService中;
  • WindowManager和WindowManagerService的交互是通过IPC进程间通信完成的;
  • 定义窗口样式和行为的抽象基类,用于作为顶层的View加到WindowManager中,其实现类是PhoneWindow;
  • 每个Window都需要指定一个Type(应用窗口、子窗口、系统窗口)。Activity对应的窗口是应用窗口;PhoneWindow,ContextMenu,OptionMenu是常用的子窗口;像Toast和系统警告提示框(如ANR)就是系统窗口,还有很多应用的悬浮窗也属于系统窗口;

3、Surface

  • 在Android中,一个窗口会独占一个Surface,Surface其实就是一个画布,应用程序通过Canvas或者OpenGL在Surface上绘制内容;
  • 在Surface上绘制后,通过SurfaceFlinger将多块Surface的内容按照Z-order进行混合并输出到FrameBuffer,从而将Android页面展示给用户;
  • 每个窗口都有一块Surface用于显示自己的ui,必然需要一个角色对窗口进行统一管理,这个时候,WMS应运而生。WMS为所有窗口分配Surface,掌管z-order以及位置、尺寸、窗口的进场出场动画,并且还是输入系统的中转站;
  • 布局系统:计算管理窗口的位置和层次;
  • 动画系统:根据布局系统的计算渲染窗口动画;

4、Window的Type

  • 应用窗口:层级范围是1~99
  • 子窗口:层级范围是1000~1999
  • 系统窗口:层级范围是2000~2999

5、窗口flags显示属性

  1. // 窗口特征标记 
  2. public int flags; 
  3. // 当该window对用户可见时,允许锁屏 
  4. public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001; 
  5. // 窗口后面的所有内容都变暗 
  6. public static final int FLAG_DIM_BEHIND        = 0x00000002; 
  7. // 窗口后面的所有内容都变模糊 
  8. public static final int FLAG_BLUR_BEHIND        = 0x00000004; 
  9. // 窗口不能获得焦点 
  10. public static final int FLAG_NOT_FOCUSABLE      = 0x00000008; 
  11. // 窗口不接受触摸屏事件 
  12. public static final int FLAG_NOT_TOUCHABLE      = 0x00000010; 
  13. // 即使在该window可获得焦点情况下,允许该窗口之处的点击事件传递到当前窗口后面的窗口去 
  14. public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020; 
  15. // 当手机处于睡眠状态,如果屏幕被按下,那么该window将第一个收到触摸事件 
  16. public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040; 
  17. // 当该window对用户可见时,屏幕处于常亮状态 
  18. public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080; 
  19. // 让window占满整个屏幕,不留任何边界 
  20. public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100; 
  21. // 允许窗口超出整个手机屏幕 
  22. public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200; 
  23. // window全名显示 
  24. public static final int FLAG_FULLSCREEN      = 0x00000400; 
  25. // 恢复window非全屏显示 
  26. public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800; 
  27. // 开启窗口抖动 
  28. public static final int FLAG_DITHER             = 0x00001000; 
  29. // 安全内容窗口,该窗口显示时不允许截屏 
  30. public static final int FLAG_SECURE             = 0x00002000; 
  31. // 一种特殊模式,在该模式下,布局参数用于在将表面合成到屏幕时执行缩放。 
  32. public static final int FLAG_SCALED             = 0x00004000; 
  33. public static final int FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000; 
  34. public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000; 
  35. public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000; 
  36. // 接收单个特殊的MotionEvent,以应对窗口外发生的触摸。  
  37. // 不会收到完整的向下/向上/向上手势,而只会收到第一次向下的位置作为ACTION_OUTSIDE。 
  38. public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000; 
  39. // 锁屏时显示该窗口 
  40. public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000; 
  41. // 系统的墙纸显示在该窗口之后 
  42. public static final int FLAG_SHOW_WALLPAPER = 0x00100000; 
  43. // 当window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕 
  44. public static final int FLAG_TURN_SCREEN_ON = 0x00200000; 
  45. // 该窗口显示,消失键盘 
  46. public static final int FLAG_DISMISS_KEYGUARD = 0x00400000; 
  47. // 当window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的 
  48. // 触摸屏可以支持split touch 
  49. public static final int FLAG_SPLIT_TOUCH = 0x00800000; 
  50. // 对该window进行硬件加速,该flag必须在activity或者dialog的content view之前进行设置 
  51. public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000; 
  52. // 让该window占满整个手机屏幕,不留任何边界 
  53. public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000; 
  54. // 透明状态栏 
  55. public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000; 
  56. // 透明导航栏 
  57. public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000; 

二、 Window的添加流程

  1. public final class WindowManagerGlobal { 
  2.      public void addView(View view, ViewGroup.LayoutParams params, 
  3.                 Display display, Window parentWindow) { 
  4.             //校验参数的合法性 
  5.             ... 
  6.             //ViewRootImpl封装了View与WindowManager的交互力促 
  7.             ViewRootImpl root; 
  8.             View panelParentView = null
  9.             synchronized (mLock) { 
  10.                 // Start watching for system property changes. 
  11.                 if (mSystemPropertyUpdater == null) { 
  12.                     mSystemPropertyUpdater = new Runnable() { 
  13.                         @Override public void run() { 
  14.                             synchronized (mLock) { 
  15.                                 for (int i = mRoots.size() - 1; i >= 0; --i) { 
  16.                                     mRoots.get(i).loadSystemProperties(); 
  17.                                 } 
  18.                             } 
  19.                         } 
  20.                     }; 
  21.                     SystemProperties.addChangeCallback(mSystemPropertyUpdater); 
  22.                 } 
  23.                 int index = findViewLocked(viewfalse); 
  24.                 if (index >= 0) { 
  25.                     if (mDyingViews.contains(view)) { 
  26.                         // Don't wait for MSG_DIE to make it's way through root's queue. 
  27.                         mRoots.get(index).doDie(); 
  28.                     } else { 
  29.                         throw new IllegalStateException("View " + view 
  30.                                 + " has already been added to the window manager."); 
  31.                     } 
  32.                     // The previous removeView() had not completed executing. Now it has. 
  33.                 } 
  34.                 // If this is a panel window, then find the window it is being 
  35.                 // attached to for future reference. 
  36.                 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && 
  37.                         wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { 
  38.                     final int count = mViews.size(); 
  39.                     for (int i = 0; i < count; i++) { 
  40.                         if (mRoots.get(i).mWindow.asBinder() == wparams.token) { 
  41.                             panelParentView = mViews.get(i); 
  42.                         } 
  43.                     } 
  44.                 } 
  45.                 //通过上下文构建ViewRootImpl 
  46.                 root = new ViewRootImpl(view.getContext(), display); 
  47.                 view.setLayoutParams(wparams); 
  48.                 //mViews存储着所有Window对应的View对象 
  49.                 mViews.add(view); 
  50.                 //mRoots存储着所有Window对应的ViewRootImpl对象 
  51.                 mRoots.add(root); 
  52.                 //mParams存储着所有Window对应的WindowManager.LayoutParams对象 
  53.                 mParams.add(wparams); 
  54.             } 
  55.             // do this last because it fires off messages to start doing things 
  56.             try { 
  57.                 //调用ViewRootImpl.setView()方法完成Window的添加并更新界面 
  58.                 root.setView(view, wparams, panelParentView); 
  59.             } catch (RuntimeException e) { 
  60.                 // BadTokenException or InvalidDisplayException, clean up. 
  61.                 synchronized (mLock) { 
  62.                     final int index = findViewLocked(viewfalse); 
  63.                     if (index >= 0) { 
  64.                         removeViewLocked(indextrue); 
  65.                     } 
  66.                 } 
  67.                 throw e; 
  68.             } 
  69.         } 

在这个方法里有三个重要的成员变量:

  • mViews 存储着所有Window对应的View对象;
  • mRoots 存储着所有Window对应的ViewRootImpl对象;
  • mParams 存储着所有Window对应的WindowManager.LayoutParams对象;
  • 这里面提到了一个我们不是很熟悉的类ViewRootImpl,它其实就是一个封装类,封装了View与WindowManager的交互方式,它是View与WindowManagerService通信的桥梁;
  • 最后也是调用ViewRootImpl.setView()方法完成Window的添加并更新界面;

我们来看看这个方法的实现

  1. public final class ViewRootImpl implements ViewParent, 
  2.         View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks { 
  3.      public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { 
  4.             synchronized (this) { 
  5.                 if (mView == null) { 
  6.                     mView = view
  7.                     //参数校验与预处理 
  8.                     ... 
  9.                     // Schedule the first layout -before- adding to the window 
  10.                     // manager, to make sure we do the relayout before receiving 
  11.                     // any other events from the system. 
  12.                     //1. 调用requestLayout()完成界面异步绘制的请求 
  13.                     requestLayout(); 
  14.                     if ((mWindowAttributes.inputFeatures 
  15.                             & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 
  16.                         mInputChannel = new InputChannel(); 
  17.                     } 
  18.                     mForceDecorViewVisibility = (mWindowAttributes.privateFlags 
  19.                             & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; 
  20.                     try { 
  21.                         mOrigWindowType = mWindowAttributes.type; 
  22.                         mAttachInfo.mRecomputeGlobalAttributes = true
  23.                         collectViewAttributes(); 
  24.                         //2. 创建WindowSession并通过WindowSession请求WindowManagerService来完成Window添加的过程 
  25.                         //这是一个IPC的过程。 
  26.                         res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, 
  27.                                 getHostVisibility(), mDisplay.getDisplayId(), 
  28.                                 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, 
  29.                                 mAttachInfo.mOutsets, mInputChannel); 
  30.                     } catch (RemoteException e) { 
  31.                         mAdded = false
  32.                         mView = null
  33.                         mAttachInfo.mRootView = null
  34.                         mInputChannel = null
  35.                         mFallbackEventHandler.setView(null); 
  36.                         unscheduleTraversals(); 
  37.                         setAccessibilityFocus(nullnull); 
  38.                         throw new RuntimeException("Adding window failed", e); 
  39.                     } finally { 
  40.                         if (restore) { 
  41.                             attrs.restore(); 
  42.                         } 
  43.                     } 
  44.                     ... 
  45.             } 
  46.         }     
  • 调用requestLayout()完成界面异步绘制的请求,requestLayout()会去调用scheduleTraversals()来完成View的绘制,scheduleTraversals()方法将一个TraversalRunnable提交到工作队列中执行View的绘制。而TraversalRunnable最终调用了performTraversals()方法来完成实际的绘制操作。提到performTraversals()方法我们已经很熟悉了;
  • 创建WindowSession并通过WindowSession请求WindowManagerService来完成Window添加的过程这是一个IPC的过程,WindowManagerService作为实际的窗口管理者,窗口的创建、删除和更新都是由它来完成的,它同时还负责了窗口的层叠排序和大小计算等工作;

performTraversals()方法的实现:

  • 获取Surface对象,用于图形绘制;
  • 调用performMeasure()方法测量视图树各个View的大小;
  • 调用performLayout()方法计算视图树各个View的位置,进行布局;
  • 调用performMeasure()方法对视图树的各个View进行绘制;

WindowManager与WindowManagerService的跨进程通信。Android的各种服务都是基于C/S结构来设计的,系统层提供服务,应用层使用服务。WindowManager也是一样,它与

WindowManagerService的通信是通过WindowSession来完成的;

首先调用ServiceManager.getService("window")获取WindowManagerService,该方法返回的是IBinder对象,然后调用IWindowManager.Stub.asInterface()方法将WindowManagerService转换为一个IWindowManager对象;

然后调用openSession()方法与WindowManagerService建立一个通信会话,方便后续的跨进程通信。这个通信会话就是后面我们用到的WindowSession;

基本上所有的Android系统服务都是基于这种方式实现的,它是一种基于AIDL实现的IPC的过程;

  1. public final class WindowManagerGlobal { 
  2.     public static IWindowSession getWindowSession() { 
  3.         synchronized (WindowManagerGlobal.class) { 
  4.             if (sWindowSession == null) { 
  5.                 try { 
  6.                     InputMethodManager imm = InputMethodManager.getInstance(); 
  7.                     //获取WindowManagerService对象,并将它转换为IWindowManager类型 
  8.                     IWindowManager windowManager = getWindowManagerService(); 
  9.                     //调用openSession()方法与WindowManagerService建立一个通信会话,方便后续的 
  10.                     //跨进程通信。 
  11.                     sWindowSession = windowManager.openSession( 
  12.                             new IWindowSessionCallback.Stub() { 
  13.                                 @Override 
  14.                                 public void onAnimatorScaleChanged(float scale) { 
  15.                                     ValueAnimator.setDurationScale(scale); 
  16.                                 } 
  17.                             }, 
  18.                             imm.getClient(), imm.getInputContext()); 
  19.                 } catch (RemoteException e) { 
  20.                     throw e.rethrowFromSystemServer(); 
  21.                 } 
  22.             } 
  23.             return sWindowSession; 
  24.         } 
  25.     } 
  26.     public static IWindowManager getWindowManagerService() { 
  27.         synchronized (WindowManagerGlobal.class) { 
  28.             if (sWindowManagerService == null) { 
  29.                 //调用ServiceManager.getService("window")获取WindowManagerService,该方法返回的是IBinder对象 
  30.                 //,然后调用IWindowManager.Stub.asInterface()方法将WindowManagerService转换为一个IWindowManager对象 
  31.                 sWindowManagerService = IWindowManager.Stub.asInterface( 
  32.                         ServiceManager.getService("window")); 
  33.                 try { 
  34.                     if (sWindowManagerService != null) { 
  35.                         ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale()); 
  36.                     } 
  37.                 } catch (RemoteException e) { 
  38.                     throw e.rethrowFromSystemServer(); 
  39.                 } 
  40.             } 
  41.             return sWindowManagerService; 
  42.         } 
  43.     } 
  44.  } 

三、 Window的删除流程

Window的删除流程也是在WindowManagerGlobal里完成

  1. public final class WindowManagerGlobal { 
  2.    public void removeView(View view, boolean immediate) { 
  3.         if (view == null) { 
  4.             throw new IllegalArgumentException("view must not be null"); 
  5.         } 
  6.         synchronized (mLock) { 
  7.             //1. 查找待删除View的索引 
  8.             int index = findViewLocked(viewtrue); 
  9.             View curView = mRoots.get(index).getView(); 
  10.             //2. 调用removeViewLocked()完成View的删除, removeViewLocked()方法 
  11.             //继续调用ViewRootImpl.die()方法来完成View的删除。 
  12.             removeViewLocked(index, immediate); 
  13.             if (curView == view) { 
  14.                 return
  15.             } 
  16.             throw new IllegalStateException("Calling with view " + view 
  17.                     + " but the ViewAncestor is attached to " + curView); 
  18.         } 
  19.     } 
  20.     private void removeViewLocked(int index, boolean immediate) { 
  21.         ViewRootImpl root = mRoots.get(index); 
  22.         View view = root.getView(); 
  23.         if (view != null) { 
  24.             InputMethodManager imm = InputMethodManager.getInstance(); 
  25.             if (imm != null) { 
  26.                 imm.windowDismissed(mViews.get(index).getWindowToken()); 
  27.             } 
  28.         } 
  29.         boolean deferred = root.die(immediate); 
  30.         if (view != null) { 
  31.             view.assignParent(null); 
  32.             if (deferred) { 
  33.                 mDyingViews.add(view); 
  34.             } 
  35.         } 
  36.     } 

我们再来看看ViewRootImpl.die()方法的实现;

  1. public final class ViewRootImpl implements ViewParent, 
  2.         View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks { 
  3.       boolean die(boolean immediate) { 
  4.             // Make sure we do execute immediately if we are in the middle of a traversal or the damage 
  5.             // done by dispatchDetachedFromWindow will cause havoc on return
  6.             //根据immediate参数来判断是执行异步删除还是同步删除 
  7.             if (immediate && !mIsInTraversal) { 
  8.                 doDie(); 
  9.                 return false
  10.             } 
  11.             if (!mIsDrawing) { 
  12.                 destroyHardwareRenderer(); 
  13.             } else { 
  14.                 Log.e(mTag, "Attempting to destroy the window while drawing!\n" + 
  15.                         "  window=" + this + ", title=" + mWindowAttributes.getTitle()); 
  16.             } 
  17.             //如果是异步删除,则发送一个删除View的消息MSG_DIE就会直接返回 
  18.             mHandler.sendEmptyMessage(MSG_DIE); 
  19.             return true
  20.         } 
  21.         void doDie() { 
  22.             checkThread(); 
  23.             if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface); 
  24.             synchronized (this) { 
  25.                 if (mRemoved) { 
  26.                     return
  27.                 } 
  28.                 mRemoved = true
  29.                 if (mAdded) { 
  30.                     //调用dispatchDetachedFromWindow()完成View的删除 
  31.                     dispatchDetachedFromWindow(); 
  32.                 } 
  33.                 if (mAdded && !mFirst) { 
  34.                     destroyHardwareRenderer(); 
  35.                     if (mView != null) { 
  36.                         int viewVisibility = mView.getVisibility(); 
  37.                         boolean viewVisibilityChanged = mViewVisibility != viewVisibility; 
  38.                         if (mWindowAttributesChanged || viewVisibilityChanged) { 
  39.                             // If layout params have been changed, first give them 
  40.                             // to the window manager to make sure it has the correct 
  41.                             // animation info. 
  42.                             try { 
  43.                                 if ((relayoutWindow(mWindowAttributes, viewVisibility, false
  44.                                         & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 
  45.                                     mWindowSession.finishDrawing(mWindow); 
  46.                                 } 
  47.                             } catch (RemoteException e) { 
  48.                             } 
  49.                         } 
  50.                         mSurface.release(); 
  51.                     } 
  52.                 } 
  53.                 mAdded = false
  54.             } 
  55.             //刷新数据,将当前移除View的相关信息从我们上面说过了三个列表:mRoots、mParms和mViews中移除。 
  56.             WindowManagerGlobal.getInstance().doRemoveView(this); 
  57.         } 
  58.         void dispatchDetachedFromWindow() { 
  59.                 //1. 回调View的dispatchDetachedFromWindow方法,通知该View已从Window中移除 
  60.                 if (mView != null && mView.mAttachInfo != null) { 
  61.                     mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false); 
  62.                     mView.dispatchDetachedFromWindow(); 
  63.                 } 
  64.                 mAccessibilityInteractionConnectionManager.ensureNoConnection(); 
  65.                 mAccessibilityManager.removeAccessibilityStateChangeListener( 
  66.                         mAccessibilityInteractionConnectionManager); 
  67.                 mAccessibilityManager.removeHighTextContrastStateChangeListener( 
  68.                         mHighContrastTextManager); 
  69.                 removeSendWindowContentChangedCallback(); 
  70.                 destroyHardwareRenderer(); 
  71.                 setAccessibilityFocus(nullnull); 
  72.                 mView.assignParent(null); 
  73.                 mView = null
  74.                 mAttachInfo.mRootView = null
  75.                 mSurface.release(); 
  76.                 if (mInputQueueCallback != null && mInputQueue != null) { 
  77.                     mInputQueueCallback.onInputQueueDestroyed(mInputQueue); 
  78.                     mInputQueue.dispose(); 
  79.                     mInputQueueCallback = null
  80.                     mInputQueue = null
  81.                 } 
  82.                 if (mInputEventReceiver != null) { 
  83.                     mInputEventReceiver.dispose(); 
  84.                     mInputEventReceiver = null
  85.                 } 
  86.                 //调用WindowSession.remove()方法,这同样是一个IPC过程,最终调用的是 
  87.                 //WindowManagerService.removeWindow()方法来移除Window。 
  88.                 try { 
  89.                     mWindowSession.remove(mWindow); 
  90.                 } catch (RemoteException e) { 
  91.                 } 
  92.                 // Dispose the input channel after removing the window so the Window Manager 
  93.                 // doesn't interpret the input channel being closed as an abnormal termination. 
  94.                 if (mInputChannel != null) { 
  95.                     mInputChannel.dispose(); 
  96.                     mInputChannel = null
  97.                 } 
  98.                 mDisplayManager.unregisterDisplayListener(mDisplayListener); 
  99.                 unscheduleTraversals(); 
  100.             } 

Window的删除流程:

  • 查找待删除View的索引(mViews.indexOf(view));
  • 调用removeViewLocked()完成View的删除, removeViewLocked()方法继续调用;ViewRootImpl.die()方法来完成View的删除;
  • ViewRootImpl.die()方法根据immediate参数来判断是执行异步删除还是同步删除,如果是异步删除则则发送一个删除View的消息MSG_DIE就会直接返回。如果是同步删除,则调用doDie()方法;
  • doDie()方法调用dispatchDetachedFromWindow()完成View的删除,在该方法里首先回调View的dispatchDetachedFromWindow方法,通知该View已从Window中移除,然后调用WindowSession.remove()方法,这同样是一个IPC过程,最终调用的是WindowManagerService.removeWindow()方法来移除Window;

四、Window的更新流程

  1. public final class WindowManagerGlobal { 
  2.     public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 
  3.         if (view == null) { 
  4.             throw new IllegalArgumentException("view must not be null"); 
  5.         } 
  6.         if (!(params instanceof WindowManager.LayoutParams)) { 
  7.             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 
  8.         } 
  9.         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; 
  10.         //更新View的LayoutParams参数 
  11.         view.setLayoutParams(wparams); 
  12.         synchronized (mLock) { 
  13.             //查找Viewd的索引,更新mParams里的参数 
  14.             int index = findViewLocked(viewtrue); 
  15.             ViewRootImpl root = mRoots.get(index); 
  16.             mParams.remove(index); 
  17.             mParams.add(index, wparams); 
  18.             //调用ViewRootImpl.setLayoutParams()完成重新布局的工作。 
  19.             root.setLayoutParams(wparams, false); 
  20.         } 
  21.     }    
  22. 我们再来看看ViewRootImpl.setLayoutParams()方法的实现。 
  23. public final class ViewRootImpl implements ViewParent, 
  24.    void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { 
  25.            synchronized (this) { 
  26.                //参数预处理 
  27.                ... 
  28.                 //如果是新View,调用requestLayout()进行重新绘制 
  29.                if (newView) { 
  30.                    mSoftInputMode = attrs.softInputMode; 
  31.                    requestLayout(); 
  32.                } 
  33.                // Don't lose the mode we last auto-computed. 
  34.                if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) 
  35.                        == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 
  36.                    mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode 
  37.                            & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) 
  38.                            | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST); 
  39.                } 
  40.                mWindowAttributesChanged = true
  41.                //如果不是新View,调用requestLayout()进行重新绘制 
  42.                scheduleTraversals(); 
  43.            } 
  44.        }  

Window的更新流程:

  • 更新View的LayoutParams参数,查找View的索引,更新mParams里的参数;
  • 调用ViewRootImpl.setLayoutParams()方法完成重新布局的工作,在setLayoutParams()方法里最终会调用scheduleTraversals();
  • 进行解码重绘制,scheduleTraversals()后续的流程就是View的measure、layout和draw流程了;

总结

 

Window的本质是什么?事实上Window是一个抽象的概念,也就是说它并不是实际存在的,它以View的形式存在,每个Window都对应着一个View和一个ViewRootImpl,Window与View通过ViewRootImpl来建立联系。推而广之,我们可以理解WindowManagerService实际管理的也不是Window,而是View,管理在当前状态下哪个View应该在最上层显示,SurfaceFlinger绘制也同样是View;

 

责任编辑:武晓燕 来源: Android开发编程
相关推荐

2021-10-15 09:19:17

AndroidSharedPrefe分析源码

2017-05-03 17:00:16

Android渲染机制

2021-09-16 06:44:04

Android进阶流程

2021-09-30 07:36:51

AndroidViewDraw

2014-07-15 17:17:31

AdapterAndroid

2021-09-10 07:31:54

AndroidAppStartup原理

2017-07-12 14:58:21

AndroidInstant Run

2021-09-08 06:51:52

AndroidRetrofit原理

2021-09-24 08:10:40

Java 语言 Java 基础

2021-08-24 07:53:28

AndroidActivity生命周期

2022-09-01 08:08:35

Android移动操作系统

2021-09-18 06:56:01

JavaCAS机制

2021-09-17 06:55:50

AndroidLayoutView

2017-01-13 22:42:15

iosswift

2022-10-11 07:43:34

AndroidSyncGradle 构建

2023-10-13 13:30:00

MySQL锁机制

2021-10-26 17:52:52

Android插件化技术

2022-11-09 08:12:07

2024-06-06 09:58:13

2021-08-18 07:56:04

AndroidRecyclerVie复用
点赞
收藏

51CTO技术栈公众号