前言
分析Windowmanager如何管理window的流程盗温。
一 Window基礎(chǔ)
添加遣蚀、更新湃窍、刪除一個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);
參數(shù)說明:
1提岔、flag,控制Window的顯示特性拆座,參數(shù)很多可自行查詢API,常用如下
FLAG_NOT_TOUCH_MODAL:Window區(qū)域內(nèi)的點(diǎn)擊事件自己處理主巍,之外的傳遞給底層Window,通常打開此標(biāo)記
FLAG_NOT_FOCUSALE:不需要焦點(diǎn),直接傳遞到底層Window
FLAG_SHOW_WHEN_LOCKED:顧名思義挪凑,顯示在鎖屏上
2孕索、type,三種類型。Window是分層的
應(yīng)用Window:層級1-99躏碳,對應(yīng)一個activity
子Window:層級1000-1999,需要在特定的父Window中搞旭,比如Dialog
系統(tǒng)Window:層級2000-2999,需添加權(quán)限SYSTEM_ALERT_WINDOW,比如狀態(tài)欄
二 過程分析
2.1 添加過程
ViewManager只是個interface,搜索源碼菇绵,實(shí)現(xiàn)類為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對應(yīng)的view翎嫡、ViewRootImpl和布局參數(shù)
ViewRootImpl:WindowManager創(chuàng)建它來管理view
最后通過ViewRootImpl.setView來設(shè)置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,其實(shí)現(xiàn)是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);
}
所以其實(shí)是WindowManagerService的addWindow永乌,這里addWindow就是WindowManagerService把window如何布置到屏幕上的具體深入細(xì)節(jié)了惑申,就不跟了。
2.2 刪除過程
WindowManagerGlobal的removeView調(diào)用
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);延時調(diào)用翅雏,最終還是會直接調(diào)用doDie();
void doDie() {
...
if (mAdded) {
dispatchDetachedFromWindow();
}
...
WindowManagerGlobal.getInstance().doRemoveView(this);
...
}
doRemoveView硝桩,刷新mViews,mRoots枚荣,mParams數(shù)據(jù)
dispatchDetachedFromWindow中主要行為三點(diǎn):
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
//調(diào)用view的dispatchDetachedFromWindow碗脊,資源回收,中止動畫線程
mView.dispatchDetachedFromWindow();
}
mAccessibilityInteractionConnectionManager.ensureNoConnection();
mAccessibilityManager.removeAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
mAccessibilityManager.removeHighTextContrastStateChangeListener(
mHighContrastTextManager);
removeSendWindowContentChangedCallback();
destroyHardwareRenderer();
//垃圾回收橄妆,清空衙伶,設(shè)為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調(diào)用害碾,最后調(diào)用到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調(diào)用performTraversals,這個就是所有view的繪制過程了丸逸,重繪時會調(diào)用relayoutWindow然后調(diào)用mWindowSession.relayout蹋艺,即WindowManagerService的relayoutWindow方法
總結(jié)
Windowmanager通過ViewRootImpl來添加、更新和刪除window,最終的實(shí)現(xiàn)都是WindowmanagerService具體實(shí)現(xiàn)黄刚。本文目的也是掌握Windowmanager管理window的流程捎谨。