public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, 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);
}
}
4、WindowManagerGlobal
(1)定义的属性:
#WindowManagerGlobal
//Window所对应的view
private final ArrayList mViews = new ArrayList();
//Window所对应的ViewRootImpl
private final ArrayList mRoots = new ArrayList();
//Window所对应的布局参数
private final ArrayList mParams =
new ArrayList();
//已经调用了removeView,但是还没完成的Window对象
private final ArraySet mDyingViews = new ArraySet();
(2)addView (Window的添加过程)
#WindowManagerGlobal
- 检查参数是否为null,如果是子Window那么还需要调整一些布局参数
- 创建ViewRootImpl并将View添加到列表中
- 通过ViewRootImpl的setView实现view的绘制 ,setView内部通过requestLayout完成异步刷新请求。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//检查参数是否为null
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);
} else {
//如果是子view需要调整一些布局参数
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
..........
//创建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//将View、ViewRootImpl、LayoutParams加入列表
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
//通过ViewRootImpl的setView实现view的绘制
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
#ViewRootImpl
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
......
//requestLayout完成异步刷新请求
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//接着通过WindowSession完成Window的添加过程。WindowSession类型为IWindowSession,是一个 //Binder对象,实现类是Session,所以Window的添加过程是一次IPC调用。
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, 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);
} finally {
if (restore) {
attrs.restore();
}
}
..........
}
}
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals(); //View绘制的入口
}
}
IWindowSession实现类Session
#Session:
final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
final WindowManagerService mService;
@Override
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);
}
}
最终的Window添加的过程交给WindowManagerService方法处理
Window添加过程:
WindowManagerImpl(实现WindowManager)—>WindowManagerGlobal(检查参数,创建ViewRootImpl将View添加到列表中)—>ViewRootImpl(更新界面)—>IWindowSession(Binder对象)—>Session(具体实现)—>
WindowManagerService(完成Window的添加)
(3)removeView (Window删除过程)
WindowManager提供两种删除接口,removeView(异步删除)和removeViewImmediate(同步删除)
#WindowManagerGlobal
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
//查找需要删除view的索引
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
removeViewLocked(index, immediate);
if (curView == view) {
return;
}
throw new IllegalStateException("Calling with view " + view
+ " but the ViewAncestor is attached to " + curView);
}
}
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()方法进行操作
#ViewRootImpl:
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;
}
异步删除通过Handler发送了MSG_DIE的消息,没有真正删除。只是将view添加到一个待删除的列表mDyingViews中。(同步删除直接调用doDie()方法)
通过Handler接收到发送的消息后,执行doDie方法。
#ViewRootImpl:
void doDie() {
checkThread();
if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
synchronized (this) {
if (mRemoved) {
return;
}
mRemoved = true;
if (mAdded) {
dispatchDetachedFromWindow(); //内部调用view的dispatchDetachedFromWindow方法
}
if (mAdded && !mFirst) {
destroyHardwareRenderer();
if (mView != null) {
int viewVisibility = mView.getVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
if (mWindowAttributesChanged || viewVisibilityChanged) {
// If layout params have been changed, first give them
// to the window manager to make sure it has the correct
// animation info.
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
}
}
mSurface.release();
}
}
mAdded = false;
}
WindowManagerGlobal.getInstance().doRemoveView(this);//调用WindowManagerGlobal刷新数据
}
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();
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 {
//调用到了mWindowSession是个Binder,最后调用是Session的remove方法。这是一个IPC过程
mWindowSession.remove(mWindow);
} catch (RemoteException 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();
}
#View
void dispatchDetachedFromWindow() {
AttachInfo info = mAttachInfo;
if (info != null) {
int vis = info.mWindowVisibility;
if (vis != GONE) {
onWindowVisibilityChanged(GONE);
}
}
onDetachedFromWindow();//view从Window移除时调用,做资源回收的工作
onDetachedFromWindowInternal();
.....
}
doDie和dispatchDetachedFromWindow的主要工作:
- 垃圾回收的工作,比如清除数据和消息,移除回调。
- 通过Session的remove方法删除Window,mWindowSession.remove(mWindow),这同样是一个IPC过程,最终会调用WindowManagerService的removeWindow方法。
- 调用View的dispatchDetachedFromWindow方法,在内部调用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。
- 调用WindowManagerGlobal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews,需要将当前Window所关联的这三类对象从列表中删除。
Window删除过程:
WindowManagerImpl(实现WindowManager)—>WindowManagerGlobal(将View添加到待删除的列表)—>ViewRootImpl(调用doDie)—>IWindowSession(Binder对象)—>Session(具体实现)—>
WindowManagerService(调用removeWindow)—>View(调用dispatchDetachedFromWindow回收资源等工作)—>WindowManagerGlobal(调用doRemoveView刷新数据)
(3)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的LayoutParams
view.setLayoutParams(wparams);
synchronized (mLock) {
//查找控件索引
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
//移除之前的LayoutParams
mParams.remove(index);
//新增LayoutParams
mParams.add(index, wparams);
//给ViewRootImpl更新
root.setLayoutParams(wparams, false);
}
}
调用View的setLayoutParams来更新View的LayoutParams
调用ViewRootImpl的setLayoutParams来更新ViewRootImpl的layoutParams
在setLayoutParams方法中调用scheduleTraversals方法
#ViewRootImpl
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
对View重新布局,包括view重新测量、布局、重绘。
ViewRootImpl通过WindowSession的relayout方法来更新Window视图,最终通过WindowManagerService的relayoutWindow()来实现,这也是IPC过程。
Window更新过程:
WindowManagerImpl(实现WindowManager)—>WindowManagerGlobal—>View(调用setLayoutParams)—>ViewRootImpl(调用setLayoutParams)—>IWindowSession(Binder对象,调用relayout)—>Session(具体实现)—>WindowManagerService(调用relayoutWindow方法)
注:开发艺术探索笔记整理