Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(一)
Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(三)- Activiy 的 Window 的創(chuàng)建過程
通過 Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(一) 已經(jīng)知道,我們能夠從 Activity 或者 Context 拿到的泛鸟,就是 WindowManager 的具體實(shí)現(xiàn) WindowManagerImpl营袜。
當(dāng)我們想要添加一個(gè) Window 的時(shí)候昙篙,就是要通過 WindowManagerImpl 的方法來實(shí)現(xiàn)茉继。更準(zhǔn)確的說翼闹,是 WindowManagerImpl 實(shí)現(xiàn)的 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 開發(fā)藝術(shù)探索》柑营,我做了一點(diǎn)修改屈雄。
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 兩個(gè)參數(shù)比較重要官套,大家可以參考網(wǎng)上的各種說明酒奶。當(dāng)然蚁孔,源碼里面也有詳細(xì)的說明。
我這個(gè)例子惋嚎,是可以直接在 activity 里面跑起來的杠氢,作用是在屏幕上坐標(biāo)為 params.x = 100; params.y = 100; 的地方添加一個(gè)按鈕。
下面另伍,我們就跟著源碼看看修然,調(diào)用 getWindowManager().addView(btn, params) 后到底發(fā)生了什么。
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 把任務(wù)轉(zhuǎn)給了 mGlobal 的 addView 方法愕宋。
看下面的代碼,再往下走结榄,就進(jìn)入了root.setView(view, wparams, panelParentView)中贝,也就是 ViewRootImpl 的方法。
// WindowManagerGlobal
public final class WindowManagerGlobal {
...
// 存儲(chǔ)所有 Window 對(duì)應(yīng)的 View
private final ArrayList<View> mViews = new ArrayList<View>();
// 存儲(chǔ)所有 Window 對(duì)應(yīng)的 ViewRootImpl
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
// 存儲(chǔ)所有 Window 對(duì)應(yīng)的布局參數(shù)
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
// 存儲(chǔ)正在被刪除的 View 對(duì)象臼朗,也就是調(diào)用了 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 會(huì)最終調(diào)用到 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视哑,它是一個(gè) Binder 對(duì)象绣否,真正的實(shí)現(xiàn)類是 Session,這是一次 IPC 調(diào)用挡毅。
我在 Window, WindowManager, WindowManagerService 的簡(jiǎn)單梳理(一) 中曾經(jīng)寫過蒜撮,WindowManagerService 是 IWindowManager 接口的實(shí)現(xiàn)。所以跪呈,這里才會(huì)和 WindowManagerService 發(fā)生關(guān)系段磨。
// 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 內(nèi)部最終是將 Window 提交給了 WindowManagerService 去處理耗绿。WindowManagerService 內(nèi)部會(huì)為每一個(gè)應(yīng)用保留一個(gè)單獨(dú)的 Session苹支。
如果再仔細(xì)看,mWindowSession 提交的是一個(gè) IWindow 對(duì)象误阻,也就是 ViewRootImpl 內(nèi)部的 mWindow對(duì)象债蜜,類型是 ViewRootImpl.W。
所以說究反,什么是 Window寻定?如果 Window 是指用來做顯示的一個(gè)抽象概念。那么奴紧,當(dāng)一個(gè)新的 Window 被添加以后特姐,WindowManagerService 中會(huì)增加一個(gè) IWindow 對(duì)象。
值得一提的是黍氮,Activity 的 Window 的創(chuàng)建唐含,也基本遵循這個(gè)過程浅浮,只不過這個(gè)過程是自動(dòng)完成的。