Framework底层服务WMS——深扒WindowManager管理机制
2024-03-29 14:53:25

Framework底层服务WMS——深扒WindowManager管理机制

一、层服WMS功能介绍

要想了解WindowManager管理机制 ,深扒首先我们先介绍WMS是理机一个非常重要的系统服务。

它支撑着视图相关的层服各项业务 ,这非常符合软件设计的深扒单一职责原则 ,其业务和ActivityManagerService(简称AMS)一起几乎占据了framework业务的理机半壁江山,可见其重要性。层服关于WMS的深扒内容实在太多了,这里只简单介绍其大致功能以及启动流程。理机

WMS的层服大概功能如下图所示:


Framework底层服务WMS——深扒WindowManager管理机制


这里先简单描述一下各项功能:

  • 窗口管理 :WMS是窗口管理者,结合WindowManager实现窗口的深扒启动 、添加、理机删除,层服以及管理窗口的深扒大小、层级等 。理机
  • 窗口动画:在窗口切换时,使用窗口动画可以使这个过程看起来更炫更生动 ,这个窗口动画就是由WMS的动画子系统来负责的,动画子系统的管理者便是WindowAnimator 。
  • 输入系统的中转站:触摸设备屏幕上的窗口时会产生触摸事件 ,InputManagerService(IMS)会对触摸事件进行处理 ,找到最合适的窗口来反馈事件。而WMS是这些窗口的管理者,那自然而然就成为了输入系统的中转站了 。
  • Surface管理 :窗口并不具备绘制功能 ,所以每个窗口都需要一个Surface来供自己绘制,WMS就是这个Surface的管理者。

二、windowManager简介

windowManager是Android的系统服务SystemService中的重要一员,用于将View动态添加、移除、更新到window中。

3个方法

// 添加viewnpublic void addView(View view, ViewGroup.LayoutParams params);nn// 更新viewnpublic void updateViewLayout(View view, ViewGroup.LayoutParams params);nn// 移除npublic void removeView(View view);

两要素

View

需要有一个被添加的View。

WindowManager.LayoutParams

WindowManager.LayoutParams也是ViewGroup.LayoutParams的一个子类 。 WindowManager.LayoutParams的参数type指定了window的类型 ,包括如下三种类型 :

  • Application windows(值从1~99),该类型window的token必须被设置成activity的token(token:标识一个window)。应用内的一些小浮球就是该类型window 。
  • Sub-windows(值从1000~1999) ,它关联于另一个顶级的window,该类型window的token必须是关联window的token。对话框就是该类型的window 。
  • System windows(值为2000~2999) ,该类型的window通常是系统因特殊目的所使用的,不应该被普通应用所使用,且使用需要申请指定的权限(系统权限中的悬浮窗权限)。系统的通知栏就是该类型window。

WindowManager.LayoutParams的参数flags用于设置各种行为 ,比如:

  • 状态栏透明(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
  • 导航栏透明(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
  • 不获取焦点(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)(注意 :如果设置该属性 ,window通过setOnKeyListener监听back事件会无效)
  • 不响应触摸事件(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)

如果要对系统UI进行设置 ,可以通过WindowManager.LayoutParams的参数systemUiVisibility 。


Framework底层服务WMS——深扒WindowManager管理机制


三 、WindowManager工作机制

WindowManager是如何将View呈现在界面的 。本文主要包含如下内容 :


Framework底层服务WMS——深扒WindowManager管理机制


一、一个悬浮按钮的demo

本demo实现了在屏幕上显示一个悬浮的Button ,并可以跟随手指的移动而移动。代码如下 :

1 public void drawFloatButton() { n 2 requestWindowPermission();n 3 final WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);n 4 final Button button = new Button(this);n 5 button.setText("button");n 6 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(n 7 WindowManager.LayoutParams.WRAP_CONTENT,n 8 WindowManager.LayoutParams.WRAP_CONTENT,n 9 0,n10 0,n11 PixelFormat.TRANSPARENT);n12 params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODALn13 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLEn14 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;n15 params.gravity = Gravity.LEFT | Gravity.TOP;n16 params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;n17 params.x = 500;n18 params.y = 500;n19 windowManager.addView(button, params);n20 button.setOnTouchListener(new View.OnTouchListener() { n21 @Overriden22 public boolean onTouch(View v, MotionEvent event) { n23 int rawX = (int) event.getRawX();n24 int rawY = (int) event.getRawY();n25 switch (event.getAction()) { n26 case MotionEvent.ACTION_MOVE:n27 params.x = rawX;n28 params.y = rawY;n29 windowManager.updateViewLayout(button, params);n30 break;n31 default:n32 break;n33 }n34 return false;n35 }n36 });n37 }

如果是在Android6.0及以上,需要处理权限问题 ,在AndroidManifest.xml中声明权限 :

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

并在代码中动态申请

1 private void requestWindowPermission() { n 2 //android 6.0或者之后的版本需要发一个intent让用户授权n 3 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { n 4 if (!Settings.canDrawOverlays(getApplicationContext())) { n 5 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,n 6 Uri.parse("package:" + getPackageName()));n 7 startActivityForResult(intent, 100);n 8 }n 9 }n10 }

由于该权限是一个敏感权限,所以启动时系统还会弹出一个界面让用户手动开启该权限 :


Framework底层服务WMS——深扒WindowManager管理机制

演示效果如下所示:

Framework底层服务WMS——深扒WindowManager管理机制

该Button是个悬浮按钮,它并不是通过在xml布局文件中加入 ,然后通过Activity的setContentView方法将其显示在界面中的 ,而是通过第19行的WindowManager.addView方法实现的。gif中可以看到,该Button可以显示到Title区域 ,也可以在app退出后(不杀死进程)独立显示在桌面上。手指滑动过程中 ,通过第29行WindowManager.updateViewLayout更新Button的LayoutParams的坐标参数,不断更新该Button的位置。后续我们会对这两个方法做详细分析 。


二、Window相关特性

通过上述的demo,我们可以看到设置了LayoutParams的flags、type变量值,它们都是用来定义Window的特性的。

1 、flag

flag变量用于设置window的属性 ,控制其显示特性 ,比如设置为不获取焦点 、不接受触屏事件 、显示在锁屏之上等  。在WindowManager.LayoutParams类中定义了很多的flag常量 ,来丰富Window的功能及属性。

2 、type

type变量用于表示Window的类型 。系统规定了Window有三种类型,按取值由小到大依次为 :

(1)应用Window:对应着一个Activity,要创建应用窗口就必须在Activity中完成 。层级范围 :1~99

(2)子Window :不能独立存在,需要依附于特定的父Window。比如Dialog,PopWindow,菜单等 。层级范围:1000~1999

(3)系统Window:拥有系统权限才能创建的Window。比如Toast 、系统状态栏、导航栏 、手机低电量提示、输入法Window 、搜索条、来电显示等 。系统Window是独立于应用程序的,理论上讲应用程序没有权限创建系统Window ,只有系统进程才有。层级范围 :2000~2999

type的值越大,在Window体系中显示的层级就越高 。为了理解这一点,我们了解一下窗口的Z-Order管理。

手机上采用的是层叠式的布局 ,它是一个三维空间 ,将手机水平方向作为X轴 ,竖直方向作为Y轴,垂直于屏幕由里向外的方向为Z轴,所有窗口就按照type值的顺序排列在Z轴上,type值越大Z值也就越大。如下图所示,所以系统Window往往会在上层显示:

Framework底层服务WMS——深扒WindowManager管理机制


三 、WindowManager关系网

1 、WindowManager在系统架构中的位置

这里咱们先通过系统架构图来直观看看WindowManager在系统架构中的位置 :

Framework底层服务WMS——深扒WindowManager管理机制

WindowManager在系统架构中的位置

上图中红色边框的“Window Manager”和“Surface Manager”都和Window直接相关,“Surface Manager”不在本文的讨论范围内 ,这里只关注“Window Manager” ,从上图可以看出,它位于Framework层。

2、WindowManager实例的获取

在前面的demo中的第三行,通过如下的方式来获取WindowManager实例 :

WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

这种方式在获取系统服务的时候非常常见 ,所以这里顺便看看其代码实现 :

1 //=============Activity.java============n 2 private WindowManager mWindowManager;n 3 private Window mWindow;n 4 @Overriden 5 public Object getSystemService(@ServiceName @NonNull String name) { n 6 if (getBaseContext() == null) { n 7 throw new IllegalStateException(n 8 "System services not available to Activities before onCreate()");n 9 }n10 if (WINDOW_SERVICE.equals(name)) { n11 return mWindowManager;n12 } else if (SEARCH_SERVICE.equals(name)) { n13 ensureSearchManager();n14 return mSearchManager;n15 }n16 return super.getSystemService(name);n17 }n18 n19 final void attach(...){ n20 mWindowManager = mWindow.getWindowManager();n21 }n22 n23 //==========Context.java==========n24 public static final String WINDOW_SERVICE = "window";n25 n26 //===========Window.java==========n27 private WindowManager mWindowManager;n28 n29 public WindowManager getWindowManager() { n30 return mWindowManager;n31 }n32 n33 public void setWindowManager(WindowManager wm, IBinder appToken, String appName,n34 boolean hardwareAccelerated) { n35 ......n36 mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);n37 }n38 n39 public WindowManagerImpl createLocalWindowManager(Window parentWindow) { n40 return new WindowManagerImpl(mContext, parentWindow);n41 }

理解上面的逻辑,需要先知道一个继承关系 :Activity extends ContextThemeWrapper extends ContextWrapper extends Context。通过上述代码可以明确了,这里获得的WindowManager的实例,实际上是WindowManagerImpl实例  。这种面向接口编程(在接口中定义方法 ,在实现类中实现)的方式很普遍,这里就不赘述了 。

3、WindowManager与ViewManager、WindowManager 、WindowManagerImpl、WindowManagerGlobal之间的关系

在分析源码前一定要捋清楚ViewManager 、WindowManager 、WindowManagerImpl 、WindowManagerGlobal之间的关系 。下面先把关键代码摆出来 :

1 public interface ViewManagern 2 { n 3 public void addView(View view, ViewGroup.LayoutParams params);n 4 public void updateViewLayout(View view, ViewGroup.LayoutParams params);n 5 public void removeView(View view);n 6 }n 7 n 8 public interface WindowManager extends ViewManager{ n 9 ......n10 }n11 n12 public final class WindowManagerImpl implements WindowManager { n13 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();n14 @overriden15 public void addView(view,params){ n16 mGlobal.addView(...);n17 }n18 public void updateViewLayout(view,params){ n19 mGlobal.updateViewLayout(...);n20 }n21 public void remove(view){ n22 mGlobal.remove(...);n23 }n24 }n25 n26 public final class WindowManagerGlobal { n27 public void addView(...){ n28 ......n29 }n30 public void updateViewLayout(...) { n31 ......n32 }n33 public void removeView(...) { n34 ......n35 }n36 }

看到上述这段代码,相信你一定已经清楚了它们之间的关系了。ViewManager是个接口 ,其中定义了三个方法  ,在Window体系中添加 、更新 、移除View的过程看起来比较复杂 ,但其实都是围绕着这三个方法展开的。WindowManager是个接口 ,继承了ViewManager,扩展了功能。WindowManagerImpl是个实现类,其中包含了WindowManagerGlobal实例 。WindowManagerGlobal则真正完成了addView、updateViewLayout 、removeView过程 。所以,在demo中我们在使用WindowManager的实例调用addView ,updateViewLayout方法时,实际上都是WindowManagerGlobal来完成的。这种方式称为桥接模式 ,这在系统源码种很常见 ,Context机制中也是这种方式 ,桥接模式这里就不展开讲了。

第13行中通过WindowManagerGlobal.getInstance()来获取的实例,这里看看其实现:

1 //=========WindowManagerGlobal.java========n 2 private static WindowManagerGlobal sDefaultWindowManager;n 3 public static WindowManagerGlobal getInstance() { n 4 synchronized (WindowManagerGlobal.class) { n 5 if (sDefaultWindowManager == null) { n 6 sDefaultWindowManager = new WindowManagerGlobal();n 7 }n 8 return sDefaultWindowManager;n 9 }n10 }

可见,它是通过单例模式的方式对外提供的实例。如果对单例模式比较了解的话,就能看出这种实现方式是有问题的(对比DCL方式),但不明白系统源码为什么要这样实现 ,可能是系统中调用该实例方法的场景比较简单吧 ,咱们自己在设计单例模式的时候可不能这样做 。

在WindowMangerGlobal.java中维护着四个非常重要的list ,这四个list在addView 、updateViewLayout、removeView的过程中都会频频出现 ,理清楚这四个list和这三个方法 ,理解WindowManager工作机制时会清晰很多,它们在下面的源码中会详细讲到 。

1 //=========WindowManagerGlobal.java=========n2 //所有Window对应的Viewn3 private final ArrayList<View> mViews = new ArrayList<View>();n4 //所有Window对应的ViewRootImpln5 private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();n6 //所有Window对应的LayoutParamsn7 private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>;n8 //正在被删除的View ,或者已经执行了removeView方法但还没有完成删除操作的Viewn9 private final ArraySet<View> mDyingViews = new ArraySet<View>;

四  、addView机制

1 //=========WindowManagerGlobal=========n 2 public void addView(View view, ViewGroup.LayoutParams params,n 3 Display display, Window parentWindow) { n 4 ......n 5 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;n 6 ......n 7 ViewRootImpl root;n 8 View panelParentView = null;n 9 synchronized (mLock) { n10 ......n11 //view不能重复添加 ,如果要添加需要先removeView,否则抛异常n12 int index = findViewLocked(view, false);n13 if (index >= 0) { n14 if (mDyingViews.contains(view)) { n15 // Don't wait for MSG_DIE to make it's way through root's queue.n16 mRoots.get(index).doDie();n17 } else { n18 throw new IllegalStateException("View " + viewn19 + " has already been added to the window manager.");n20 }n21 // The previous removeView() had not completed executing. Now it has.n22 }n23 //子windown24 // If this is a panel window, then find the window it is beingn25 // attached to for future reference.n26 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&n27 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { n28 final int count = mViews.size();n29 for (int i = 0; i < count; i++) { n30 if (mRoots.get(i).mWindow.asBinder() == wparams.token) { n31 panelParentView = mViews.get(i);n32 }n33 }n34 }n35 root = new ViewRootImpl(view.getContext(), display);n36 view.setLayoutParams(wparams);n37 mViews.add(view);n38 mRoots.add(root);8n39 mParams.add(wparams);n40 // do this last because it fires off messages to start doing thingsn41 try { n42 root.setView(view, wparams, panelParentView);n43 } catch (RuntimeException e) { n44 // BadTokenException or InvalidDisplayException, clean up.n45 if (index >= 0) { n46 removeViewLocked(index, true);n47 }n48 throw e;n49 }n50 }n51 }

上述代码中除了关键方法外,注意留意mViews、mRoots 、mParams集合的操作。

1 //=========ViewRootImpl.java========== n 2 /**n 3 * We have one childn 4 */n 5 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { n 6 synchronized (this) { n 7 if (mView == null) { n 8 mView = view;n 9 ......n10 mAdded = true;n11 int res; /* = WindowManagerImpl.ADD_OKAY; */n12 // Schedule the first layout -before- adding to the windown13 // manager, to make sure we do the relayout before receivingn14 // any other events from the system.n15 requestLayout();n16 ......n17 try { n18 ......n19 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,n20 getHostVisibility(), mDisplay.getDisplayId(),n21 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,n22 mAttachInfo.mOutsets, mInputChannel);n23 } catch (RemoteException e) { n24 mAdded = false;n25 mView = null;n26 ......n27 throw new RuntimeException("Adding window failed", e);n28 } finally { n29 ......n30 }n31 ......n32 }n33 }n34 }

这里简单截取了一段UML图 ,读者明白其作用就可以了,想深入研究的可以去这篇文章看看 。


Framework底层服务WMS——深扒WindowManager管理机制

第19行的mWindowSession.addToDisplay(...)方法,addView的实际逻辑处理就在这里面。我们继续分析mWindowSession和addToDisplay(...)的逻辑 :

1 //========ViewRootImpl.java=========n 2 public final class ViewRootImpl{ n 3 final IWindowSession mWindowSession;n 4 public ViewRootImpl(...){ n 5 ......n 6 mWindowSession = WindowManagerGlobal.getWindowSession();n 7 ......n 8 }n 9 }n10 n11 //=======WindowManagerGlobal.java==========n12 public static IWindowSession getWindowSession() { n13 synchronized (WindowManagerGlobal.class) { n14 if (sWindowSession == null) { n15 try { n16 ......n17 IWindowManager windowManager = getWindowManagerService();n18 sWindowSession = windowManager.openSession(n19 new IWindowSessionCallback.Stub() { n20 @Overriden21 public void onAnimatorScaleChanged(float scale) { n22 ValueAnimator.setDurationScale(scale);n23 }n24 },n25 ......n26 } catch (RemoteException e) { n27 throw e.rethrowFromSystemServer();n28 }n29 }n30 return sWindowSession;n31 }n32 }n33 n34 public static IWindowManager getWindowManagerService() { n35 synchronized (WindowManagerGlobal.class) { n36 if (sWindowManagerService == null) { n37 sWindowManagerService = IWindowManager.Stub.asInterface(n38 ServiceManager.getService("window"));n39 ......n40 }n41 return sWindowManagerService;n42 }n43 }n44 n45 //============WindowManagerService.java=======n46 @Overriden47 public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,n48 IInputContext inputContext) { n49 if (client == null) throw new IllegalArgumentException("null client");n50 if (inputContext == null) throw new IllegalArgumentException("null inputContext");n51 Session session = new Session(this, callback, client, inputContext);n52 return session;n53 }n54 n55 public int addWindow(Session session, IWindow client, int seq,n56 WindowManager.LayoutParams attrs, int viewVisibility, int displayId,n57 Rect outContentInsets, Rect outStableInsets, Rect outOutsets,n58 InputChannel outInputChannel) { n59 //在wms中真正实现n60 ......n61 }n62 n63 //===========Session.java=========n64 final WindowManagerService mService;n65 public Session(WindowManagerService service, ......) { n66 mService = service;n67 ......n68 }n69 n70 @Overriden71 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,n72 int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,n73 Rect outOutsets, InputChannel outInputChannel) { n74 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,n75 outContentInsets, outStableInsets, outOutsets, outInputChannel);n76 }

这里面的代码逻辑很容易理解,最后是把addView的工作交给了WMS的addWindow方法,所以真正添加view的逻辑是在WMS中完成的。这里面逻辑比较复杂繁琐,就不继续深入了 ,当目前为止就已经清楚整个流程了 。


五 、updateViewLayout更新机制

1 //============WindowManagerGlobal.java==========n 2 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { n 3 ......n 4 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;n 5 view.setLayoutParams(wparams);n 6 synchronized (mLock) { n 7 int index = findViewLocked(view, true);n 8 ViewRootImpl root = mRoots.get(index);n 9 mParams.remove(index);n10 mParams.add(index, wparams);n11 root.setLayoutParams(wparams, false);n12 }n13 }

这里面对mParams进行了操作 ,将旧有的LayoutParams进行了替换 。第11行执行了更新逻辑 :

1 //=============ViewRootImpl.java==========n2 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { n3 ...... //对新的LayoutParams参数做一些操作n4 scheduleTraversals(); //调用绘制流程n5 }

从上述过程可以发现更新过程相对比较简单,更新view的过程简单来说就是,将新的LayoutParams替换掉旧的,并启用绘制流程。


六 、removeView移除机制

1 //============WindowManagerImpl.java==========n2 @Overriden3 public void removeView(View view) { n4 mGlobal.removeView(view, false);n5 }n6 @Overriden7 public void removeViewImmediate(View view) { n8 mGlobal.removeView(view, true);n9 }

WindowManagerImpl类中提供了两个方法用于移除view ,从方法名称可以推测其差别在于Immediate,也就是是否立即移除的意思。

1 //==========WindowManagerGlobal.java=========n 2 public void removeView(View view, boolean immediate) { n 3 ......n 4 synchronized (mLock) { n 5 int index = findViewLocked(view, true);n 6 View curView = mRoots.get(index).getView();n 7 removeViewLocked(index, immediate);n 8 ......n 9 }n10 }n11 n12 private void removeViewLocked(int index, boolean immediate) { n13 ViewRootImpl root = mRoots.get(index);n14 View view = root.getView();n15 ......n16 boolean deferred = root.die(immediate);n17 if (view != null) { n18 view.assignParent(null);n19 if (deferred) { n20 mDyingViews.add(view);n21 }n22 }n23 }n24 n25 //========ViewRootImpl.java=========n26 private final static int MSG_DIE = 3;n27 final ViewRootHandler mHandler = new ViewRootHandler();n28 /**n29 * @param immediate True, do now if not in traversal. False, put on queue and do later.n30 * @return True, request has been queued. False, request has been completed.n31 */n32 boolean die(boolean immediate) { n33 // Make sure we do execute immediately if we are in the middle of a traversal or the damagen34 // done by dispatchDetachedFromWindow will cause havoc on return.n35 if (immediate && !mIsInTraversal) { n36 doDie();n37 return false;n38 }n39 ......n40 mHandler.sendEmptyMessage(MSG_DIE);n41 return true;n42 }n43 n44 final class ViewRootHandler extends Handler { n45 ......n46 @Overriden47 public void handleMessage(Message msg) { n48 switch (msg.what) { n49 case MSG_DIE:n50 doDie();n51 break;n52 ......n53 }n54 }n55 }

如上代码验证了之前的猜想 ,removeView(View)和removeViewImmediate(View)的区别确实就在于是否立即移除 。如果调用removeView,会通过handler来调用doDie()  ,而我们知道handler对应了一个MessageQueue的  ,需要排队等待执行的 ,这样就实现了延后执行。而如果调用removeViewImmediate,如果当前没有执行view的遍历,那就直接调用doDie()了 。

1 //==========ViewRootImpl.java========n 2 void doDie() { n 3 ......n 4 synchronized (this) { n 5 if (mRemoved) { n 6 return;n 7 }n 8 mRemoved = true;n 9 if (mAdded) { n10 dispatchDetachedFromWindow();n11 }n12 ......n13 mAdded = false;n14 }n15 WindowManagerGlobal.getInstance().doRemoveView(this);n16 }n17 //移除的主要逻辑都在该方法内完成n18 void dispatchDetachedFromWindow() { n19 mView.dispatchDetachedFromWindow();n20 ......n21 try { n22 mWindowSession.remove(mWindow);n23 } catch (RemoteException e) { n24 }n25 ......n26 unscheduleTraversals();//停止绘制Viewn27 }n28 n29 //======View.java======n30 void dispatchDetachedFromWindow() { n31 ......n32 onDetachedFromWindow();n33 ......n34 }n35 n36 @CallSupern37 protected void onDetachedFromWindow() { n38 //在view从window移除后会回调该方法 ,可以在其中做一些资源回收的操作,如终止动画、停止线程等。n39 }n40 n41 //========WindowManagerGlobal.java=======n42 //该方法主要用于刷新数据n43 void doRemoveView(ViewRootImpl root) { n44 synchronized (mLock) { n45 final int index = mRoots.indexOf(root);n46 if (index >= 0) { n47 mRoots.remove(index);n48 mParams.remove(index);n49 final View view = mViews.remove(index);n50 mDyingViews.remove(view);n51 }n52 }n53 ......n54 }n55 n56 //==========Session.java=======n57 @Overriden58 public void remove(IWindow window) { n59 mService.removeWindow(this, window);n60 }n61 n62 //==========WindowManagerService.java=======n63 void removeWindow(Session session, IWindow client) { n64 synchronized(mWindowMap) { n65 WindowState win = windowForClientLocked(session, client, false);n66 if (win == null) { n67 return;n68 }n69 win.removeIfPossible();n70 }n71 }

上述doDie()过程比较容易理解,第22行 ,参考addView中的逻辑分析可知,这里也是IPC方式 ,流程最终进入到了WMS中的removeWindow方法,同样到这里咱们不继续往下深入了 。上述流程中 ,mRoots、mParams 、mViews、mDyingViews四个集合也做了相应的操作。

上面讲到的三个主要方法中,可以看到它们都对mRoots、mParams 、mViews、mDyingViews进行了刷新 。

文末

学到越深 ,发现需要学的越多!本文目的也是掌握Windowmanager管理window的流程。关于更多Android学习,我这里整理出一套系统性的学习资料Android进阶供大家深入了解进阶 , 总而言之来讲,WindowManager 是一个非常棒的窗口管理软件。

需要学习资料可以:私信发送“核心笔记”或“手册”即可领取资料,以及其他Android进阶资料!

(作者:汽车音响)