Window和WindowManager

    xiaoxiao2021-03-26  21

    Window和WindowManager

    Window是一个抽象的概念,每一个Window都对应一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。

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

    Window实际上是View的直接管理者

    Android中所有的视图都是通过Window来呈现的,不管是Activity、Dialog还是Toast,它们的视图实际上是附加在Window上的。

    Window的类型

    应用Window

    对应着一个Activity

    子Window

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

    系统Window

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

    Window的层级

    层级大的Window会覆盖层级小的Window,层级对应于WindowManager.LayoutParams的type参数。

    应用Window层级范围:1~999 子Window的层级范围:1000~1999 系统Window的层级范围:2000~2999

    WindowManger

    Window通过WindowManager来访问,WindowManager是一个接口,它的真正实现是WindowManagerImpl。而WindowmanagerImpl的增删更新View都交由WindowManagerGlobal来处理。

    public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); @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的几个重要的参数

    //存储所有Window所对应的View private final ArrayList<View> mViews = new ArrayList<View>(); //存储所有Window所对应的ViewRootImpl private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); //存储所有Window所对应的布局参数 private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); //存储即将被删除的View对象 (已经调用removeView方法但是删除操作还未完成的Window对象) private final ArraySet<View> mDyingViews = new ArraySet<View>();

    Window的添加过程

    Window的添加过程通过WindowManager的addView来实现

    WindowManagerGlobal的addView()

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

    if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (display == null) { throw new IllegalArgumentException("display must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); }

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

    root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams);

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

    //setView->requestLayout-> ... -> performTraversals -> 开始measure、layout、draw三大流程 root.setView(view, wparams, panelParentView);

    在来看ViewRootImpl#setView(),Window的添加请求最终交给WindowManagerService处理。

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { //... //[重要方法] requestLayout-> ... -> performTraversals -> 开始measure、layout、draw三大流程 requestLayout(); //... try { //通过WindowSession最终完成Window的添加 //mWindowSession是IWindowSession,它是一个Binder对象 [IPC调用] //mWindowSession.addToDisplay -> WindowmanagerService.addWindow mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocus(null, null); throw new RuntimeException("Adding window failed", e); } //... }

    WIndow的删除过程

    public void removeView(View view, boolean immediate) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } synchronized (mLock) { int index = findViewLocked(view, true); View curView = mRoots.get(index).getView(); //通过index查找待删除的View removeViewLocked(index, immediate); if (curView == view) { return; } throw new IllegalStateException("Calling with view " + view + " but the ViewAncestor is attached to " + curView); } }

    再来看removeViewLocked

    private void removeViewLocked(int index, boolean immediate) { ViewRootImpl root = mRoots.get(index); View view = root.getView(); if (view != null) { InputMethodManager imm = InputMethodManager.getInstance(); if (imm != null) { imm.windowDismissed(mViews.get(index).getWindowToken()); } } 具体的删除操作 boolean deferred = root.die(immediate); if (view != null) { view.assignParent(null); if (deferred) { mDyingViews.add(view); } } }

    再来看die方法。如果是同步删除,立即调用doDie(),如果是异步调用,会通过Handler发送消息调用doDie()。

    boolean die(boolean immediate) { // Make sure we do execute immediately if we are in the middle of a traversal or the damage // done by dispatchDetachedFromWindow will cause havoc on return. //立即删除 -> 同步删除 (不推荐,容易发生意外) if (immediate && !mIsInTraversal) { doDie(); return false; } if (!mIsDrawing) { destroyHardwareRenderer(); } else { Log.e(TAG, "Attempting to destroy the window while drawing!\n" + " window=" + this + ", title=" + mWindowAttributes.getTitle()); } //异步删除 mHandler.sendEmptyMessage(MSG_DIE); return true; }

    再来看doDie()

    void doDie() { //... //真正删除View dispatchDetachedFromWindow(); //... }

    dispatchDetachedFromWindow主要做4件事

    垃圾回收相关的工作,比如清除数据和消息,移除回调。 通过Session的remove方法删除Window:mWindowSession.remove(mWindow),这同样是一个IPC过程,最终会调用WindowManagerService的removeWindow方法。 调用View的dispatchDetachedFromWindow方法,在内部会调用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。调用WindowManagerGlobal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews,需要将当前Window所关联的这三个对象从列表中删除。

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

    Window的更新过程

    public void updateViewLayout(View view, ViewGroup.LayoutParams params) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; view.setLayoutParams(wparams); synchronized (mLock) { int index = findViewLocked(view, true); ViewRootImpl root = mRoots.get(index); mParams.remove(index); mParams.add(index, wparams); //更新LayoutParams -> scheduleTraversals -> ... -> 开始measure、layout、draw三大流程 root.setLayoutParams(wparams, false); } }

    window的更新通过WindowManagerGlobal#updateViewLayout()来完成,内部通过调用VIewRootImpl的setLayoutParams(),然后经过一些列的方法,最终会开始measure、layout、draw三大流程,从而实现window的更新。

    其他

    参考 《Android艺术开发探索》

    转载请注明原文地址: https://ju.6miu.com/read-659672.html

    最新回复(0)