Window, WindowManager, WindowManagerService 的简单梳理(一)
Window, WindowManager, WindowManagerService 的简单梳理(三)- Activiy 的 Window 的创建过程
通过 Window, WindowManager, WindowManagerService 的简单梳理(一) 已经知道,我们能够从 Activity 或者 Context 拿到的,就是 WindowManager 的具体实现 WindowManagerImpl。
当我们想要添加一个 Window 的时候,就是要通过 WindowManagerImpl 的方法来实现。更准确的说,是 WindowManagerImpl 实现的 ViewManager 接口的方法。
public interface ViewManager
{
/**
* Assign the passed LayoutParams to the passed View and add the view to the window.
* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
* errors, such as adding a second view to a window without removing the first view.
* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
* secondary {@link Display} and the specified display can't be found
* (see {@link android.app.Presentation}).
* @param view The view to be added to this window.
* @param params The LayoutParams to assign to view.
*/
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
下面的例子是参考任玉刚的《Android 开发艺术探索》,我做了一点修改。
Button btn = new Button(this);
btn.setText("WMS Demo");
WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
1, 0, PixelFormat.TRANSPARENT);
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
params.gravity = Gravity.LEFT | Gravity.TOP;
params.x = 100;
params.y = 100;
getWindowManager().addView(btn, params);
其中,WindowManager.LayoutParams 的 type 和 flags 两个参数比较重要,大家可以参考网上的各种说明。当然,源码里面也有详细的说明。
我这个例子,是可以直接在 activity 里面跑起来的,作用是在屏幕上坐标为 params.x = 100; params.y = 100; 的地方添加一个按钮。
下面,我们就跟着源码看看,调用 getWindowManager().addView(btn, params) 后到底发生了什么。
Window 的添加过程
// WindowManagerImpl
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, mContext.getDisplay(), mParentWindow);
}
...
}
可见,WindowManagerImpl 把任务转给了 mGlobal 的 addView 方法。
看下面的代码,再往下走,就进入了root.setView(view, wparams, panelParentView),也就是 ViewRootImpl 的方法。
// WindowManagerGlobal
public final class WindowManagerGlobal {
...
// 存储所有 Window 对应的 View
private final ArrayList<View> mViews = new ArrayList<View>();
// 存储所有 Window 对应的 ViewRootImpl
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
// 存储所有 Window 对应的布局参数
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
// 存储正在被删除的 View 对象,也就是调用了 removeView 方法,但是删除操作还未完成的 View
private final ArraySet<View> mDyingViews = new ArraySet<View>();
...
public void addView(View view, ViewGroup.LayoutParams params,
Display display, 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 WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
...
ViewRootImpl root;
View panelParentView = null;
...
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 {
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 的 setView 会最终调用到 mWindowSession.addToDisplay()。
// ViewRootImpl
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
...
final IWindowSession mWindowSession;
final W mWindow;
...
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mWindow = new W(this);
...
}
...
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...
int res; /* = WindowManagerImpl.ADD_OKAY; */
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
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 绘制的入口
scheduleTraversals();
}
}
...
static class W extends IWindow.Stub {
private final WeakReference<ViewRootImpl> mViewAncestor;
private final IWindowSession mWindowSession;
W(ViewRootImpl viewAncestor) {
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
}
...
}
}
mWindowSession 的类型是 IWindowSession,它是一个 Binder 对象,真正的实现类是 Session,这是一次 IPC 调用。
我在 Window, WindowManager, WindowManagerService 的简单梳理(一) 中曾经写过,WindowManagerService 是 IWindowManager 接口的实现。所以,这里才会和 WindowManagerService 发生关系。
// WindowManagerGlobal
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;
}
}
// Session
final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
final WindowManagerService mService;
...
public Session(WindowManagerService service, IWindowSessionCallback callback,
IInputMethodClient client, IInputContext inputContext) {
mService = service;
...
}
...
@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);
}
}
可见,mWindowSession 内部最终是将 Window 提交给了 WindowManagerService 去处理。WindowManagerService 内部会为每一个应用保留一个单独的 Session。
如果再仔细看,mWindowSession 提交的是一个 IWindow 对象,也就是 ViewRootImpl 内部的 mWindow对象,类型是 ViewRootImpl.W。
所以说,什么是 Window?如果 Window 是指用来做显示的一个抽象概念。那么,当一个新的 Window 被添加以后,WindowManagerService 中会增加一个 IWindow 对象。
值得一提的是,Activity 的 Window 的创建,也基本遵循这个过程,只不过这个过程是自动完成的。
网友评论