前言
分析Windowmanager如何管理window的流程。
一 Window基础
添加、更新、删除一个Window:
Button mButton = new Button(this);
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,0,0, PixelFormat.TRANSPARENT);
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mLayoutParams.x = 10;
mLayoutParams.y = 11;
//add
windowManager.addView(mButton,mLayoutParams);
//update
mLayoutParams.x = 100;
windowManager.updateViewLayout(mButton,mLayoutParams);
//remove
windowManager.removeView(mButton);
参数说明:
1、flag,控制Window的显示特性,参数很多可自行查询API,常用如下
FLAG_NOT_TOUCH_MODAL:Window区域内的点击事件自己处理,之外的传递给底层Window,通常打开此标记
FLAG_NOT_FOCUSALE:不需要焦点,直接传递到底层Window
FLAG_SHOW_WHEN_LOCKED:顾名思义,显示在锁屏上
2、type,三种类型。Window是分层的
应用Window:层级1-99,对应一个activity
子Window:层级1000-1999,需要在特定的父Window中,比如Dialog
系统Window:层级2000-2999,需添加权限SYSTEM_ALERT_WINDOW,比如状态栏
二 过程分析
2.1 添加过程
ViewManager只是个interface,搜索源码,实现类为WindowManagerImpl
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
然后交给代理类mGlobal即WindowManagerGlobal
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
...
try {
root.setView(view, wparams, panelParentView);
}
...
}
mViews,mRoots,mParams是三个ArrayList,用来保存所有window对应的view、ViewRootImpl和布局参数
ViewRootImpl:WindowManager创建它来管理view
最后通过ViewRootImpl.setView来设置view
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
...
然后是mWindowSession.addToDisplay,其实现是Session.addToDisplay
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
所以其实是WindowManagerService的addWindow,这里addWindow就是WindowManagerService把window如何布置到屏幕上的具体深入细节了,就不跟了。
2.2 删除过程
WindowManagerGlobal的removeView调用
removeViewLocked(index, immediate);
即
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);
}
}
}
ViewRootImpl.die
boolean die(boolean immediate) {
if (DEBUG_LIFECYCLE) {
Log.v(mTag, "die: immediate = " + immediate + ", mIsInTraversal = " + mIsInTraversal
+ ",mIsDrawing = " + mIsDrawing + ",this = " + this);
}
// 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(mTag, "Attempting to destroy the window while drawing!\n" +
" window=" + this + ", title=" + mWindowAttributes.getTitle());
}
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
mHandler.sendEmptyMessage(MSG_DIE);延时调用,最终还是会直接调用doDie();
void doDie() {
...
if (mAdded) {
dispatchDetachedFromWindow();
}
...
WindowManagerGlobal.getInstance().doRemoveView(this);
...
}
doRemoveView,刷新mViews,mRoots,mParams数据
dispatchDetachedFromWindow中主要行为三点:
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
//调用view的dispatchDetachedFromWindow,资源回收,中止动画线程
mView.dispatchDetachedFromWindow();
}
mAccessibilityInteractionConnectionManager.ensureNoConnection();
mAccessibilityManager.removeAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
mAccessibilityManager.removeHighTextContrastStateChangeListener(
mHighContrastTextManager);
removeSendWindowContentChangedCallback();
destroyHardwareRenderer();
//垃圾回收,清空,设为null
setAccessibilityFocus(null, null);
mView.assignParent(null);
mView = null;
mAttachInfo.mRootView = null;
mSurface.release();
if (mInputQueueCallback != null && mInputQueue != null) {
mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
mInputQueue.dispose();
mInputQueueCallback = null;
mInputQueue = null;
}
if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
mInputEventReceiver = null;
}
try {
//Session,IPC调用,最后调用到WindowManagerService的removeWindow,类似addview
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
Log.e(mTag, "RemoteException remove window " + mWindow + " in " + this, e);
}
// Dispose the input channel after removing the window so the Window Manager
// doesn't interpret the input channel being closed as an abnormal termination.
if (mInputChannel != null) {
mInputChannel.dispose();
mInputChannel = null;
}
//
mDisplayManager.unregisterDisplayListener(mDisplayListener);
unscheduleTraversals();
}
跟新过程
WindowManagerGlobal的updateViewLayout
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);
root.setLayoutParams(wparams, false);
}
}
ViewRootImpl.setLayoutParams刷新LayoutParams
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
...
//重新布局,包含测量,布局,重绘
scheduleTraversals();
...
}
然后看scheduleTraversals,其中有一句
```javascript
mHandler.post(mTraversalRunnable);
mTraversalRunnable调用performTraversals,这个就是所有view的绘制过程了,重绘时会调用relayoutWindow然后调用mWindowSession.relayout,即WindowManagerService的relayoutWindow方法
总结
Windowmanager通过ViewRootImpl来添加、更新和删除window,最终的实现都是WindowmanagerService具体实现。本文目的也是掌握Windowmanager管理window的流程。