安卓中是由WindowManagerService来管理所有的窗口,下面来看下Activity是如何与WindowManagerService交互,控制应用界面的添加与删除的
我们通常都是在onCreate方法中调用setContentView来设置布局,此时只是完成了视图树的创建,并没有通知WindowManagerService添加界面,真正添加界面是在回调完onResume完成的
我们的Activity都是在ActivityThread中创建,并回调Activity的各种生命周期的,调用onResume的方法为handleResumeActivity
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
......
r = performResumeActivity(token, clearHide, reason);
......
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
......
}
在handleResumeActivity中是通过performResumeActivity完成Activity的onResume回调的,之后会调用Activity的makeVisible方法
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
如果界面没有被添加,就调用ViewManager的addView方法
ViewManager是一个接口,在这里它是指WindowManagerImpl类,看下他的addView方法
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
其中mGlobal是一个WindowManagerGlobal对象,而且他本身是一个单例
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
接着看WindowManagerGlobal的addView方法
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......
ViewRootImpl root;
......
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
root.setView(view, wparams, panelParentView);
}
逻辑也很简单,就是先判断参数的正确性,接着创建一个ViewRootImpl对象,然后将数据添加到数组中,最后调用ViewRootImpl的setView方法,接着去看setView方法
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
......
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
......
}
代码有点长,但是重要的也就是上面这句,调用mWindowSession的addToDisplay方法
mWindowSession是一个IWindowSession对象,他是在ViewRootImpl的构造方法中被创建的
mWindowSession = WindowManagerGlobal.getWindowSession();
可以看到他也是一个单例
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
可以看到mWindowSession是由WindowManagerService调用openSession方法创建的,且每一个应用只有一个mWindowSession对象,而且他还是一个binder,我们的应用通过它可以与WindowManagerService交互
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext);
return session;
}
回到setView方法,看看mWindowSession,也就是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);
}
其中mService就是WindowManagerService,方法addWindow也很明显就是将我们的窗口添加进来
以上就实现了我们Activity界面的添加,接着看看Activity界面是如何被删除的
Activity界面的添加是在执行完onResume后完成的,而Activity界面被删除则是在执行完onDestroy后完成的(注意我这里说的删除不是不可见)
ActivityThread调用onDestroy的方法为handleDestroyActivity
private void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
......
wm.removeViewImmediate(v);
......
}
回调onDestroy是由performDestroyActivity完成的,之后会调用WindowManager的removeViewImmediate方法,参数v就是Activity对应的布局,也就是顶层的View : DecorView,wm也就是我们前面说的WindowManagerImpl
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}
还是调用了WindowManagerGlobal的removeView方法
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();
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);
}
}
}
可以看到又调用了removeViewLocked方法,然后根据传递进来的View找到对应的ViewRootImpl对象,然后调用ViewRootImpl的die方法,参数immediate为true
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(mTag, "Attempting to destroy the window while drawing!\n" +
" window=" + this + ", title=" + mWindowAttributes.getTitle());
}
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
又执行到了doDie上
void doDie() {
......
dispatchDetachedFromWindow();
......
}
起作用的是dispatchDetachedFromWindow方法
void dispatchDetachedFromWindow() {
......
mWindowSession.remove(mWindow);
......
}
mWindowSession之前说过是专门和WindowManagerService交互的
public void remove(IWindow window) {
mService.removeWindow(this, window);
}
Session对象又调用了WindowManagerService的removeWindow方法,之后的工作就交给了WindowManagerService完成
如此就实现了Activity界面的删除