首页 > 学院 > 开发设计 > 正文

Window和WindowManager

2019-11-09 18:37:51
字体:
来源:转载
供稿:网友

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所对应的Viewprivate final ArrayList<View> mViews = new ArrayList<View>();//存储所有Window所对应的ViewRootImplprivate 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艺术开发探索》


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表