Window 的添加过程是通过 WindowManager 的 addView
来实现的,WindowManager 是一个接口,实现类是WindowManagerImpl,因此直接看该类的addView()
.
@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);
}
上面代码可以看到,WindowManagerImpl 并没有直接实现三大操作,而是通过桥接模式将操作委托给WindowManagerGlobal,接着看WindowManagerGlobal 中的addView 方法:
/**
* WindowManager.LayoutParams继承了ViewGroup.LayoutParams
*/
public void addView(View view, ViewGroup.LayoutParams params,
Display display, android.view.Window parentWindow) {
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 android.view.WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final android.view.WindowManager.LayoutParams wparams = (android.view.WindowManager.LayoutParams) params;
/**
* 如果是子Window,那么还需要调整一些布局参数
*/
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
/**
* 如果没有父Window,则设置该视图硬件加速
*/
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
/**
* 创建ViewRootImpl(不是DecorView),是native层与java层View系统通信的桥梁。
* WMS运行在Native层的。
* 有的版本中ViewRootImpl继承了Handler类,我们熟知的performTraversals()就是系统收到绘制View的消息之后,
* 通过调用视图树的各个节点的measure、layout和draw方法来绘制整棵视图树
*/
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
/**
* 添加到列表中
*/
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
/**
* 将View显示在手机上
* 与WMS建立连接后就调用ViewRootImpl的setView方法了
* 该方法会向WMS发起显示Dialog或者Activity的DecorView请求
*/
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
root = new ViewRootImpl(view.getContext(), display)
方法比较重要,看构造方法的代码:
public ViewRootImpl(Context context, Display display) {
mContext = context;
/**
* 获取Window Session,也就是与WindowManagerService(Native层)建立连接
*/
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
/**
* 保存当前线程,更新UI的线程只能是创建ViewRootImpl的线程
* 在应用开发中,如果在子线程中更新UI会抛出异常,并不是因为只能在UI线程才能更新UI,而是因为
* ViewRootImpl是在UI线程中创建的
*/
mThread = Thread.currentThread();
}
其中WindowManagerGlobal.getWindowSession();
是在WindowManagerGlobal中:
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
/**
* 1、获取WindowManagerService
* FrameWork层通过 getWindowManagerService 获取到IWindowManager 对象(Binder)
*/
IWindowManager windowManager = getWindowManagerService();
/**
* 2、和WindowManagerService建立一个session(IWindowSession)
* 相当于Framework和Native层建立一个长期合作的办事处,双方有什么需求通过这个Session来交换信息
*/
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;
}
}
FrameWok 与 WMS 建立Session 之后就调用了 ViewRootImpl 的setView
方法:
WindowManagerDlobal中的addView:
try {
/**
* 将View显示在手机上
* 与WMS建立连接后就调用ViewRootImpl的setView方法了
* 该方法会向WMS发起显示Dialog或者Activity的DecorView请求
*/
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
ViewRootImpl.setView:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
/**
* 关注1:请求布局(异步刷新请求),对整个Window的视图进行measure、layout、draw
*/
requestLayout();
/**
* 向WMS发起显示当前window的请求
* mWindowSession的类型是IWindowSession,是一个Binder对象,真正的实现类是Session
* 是一次远程调用方法的过程(IPC过程)
*/
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
未完待续:requestLayout();