一、窗口的三种形式
Activity
:独立的页面窗口,拥有完整生命周期。这种是最常用的方式。Dialog
:对话框形式的窗口,依赖Activity
上下文。
java
Dialog dlg = new Dialog(context);
dlg.addContentView(makeView(), new LayoutParams(300, 400));
dlg.setCancelable(true);
dlg.setCanceledOnTouchOutside(true);
dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
Looper.myLooper().quit();
}
});
dlg.setTitle("Not Looper.getMainLooper() check");
dlg.show();
3.View
:通过WindowManager.addView
直接添加到系统中。系统中有很多窗口就是通过这种方式添加到系统中的。比如状态栏,虚拟导航条,小圆点啥的。第三方app也可以通过这种方式添加浮动窗口。
二、核心接口
-
App获取IWindowManager接口
WindowManager是接口类, WindowManagerImpl是WindowManager的实现。WindowManagerGlobal相当于WindowManagerImpl内部的代理,它才是真正和WMS通过IWindowManager通信的类。获取IWindowManager的代码如下:
csharp
WindowManagerGlobal.java
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
if (sWindowManagerService != null) {
ValueAnimator.setDurationScale(
sWindowManagerService.getCurrentAnimatorScale());
sUseBLASTAdapter = sWindowManagerService.useBLAST();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
-
App获取IWindowSession接口
每个 App 进程都有一个公用的
IWindowSession
,保存在WindowManagerGlobal
中。可通过adb shell dumpsys window s
查看所有 session,获取代码如下:
java
WindowManagerGlobal.java
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// Emulate the legacy behavior. The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
-
窗口添加的核心实现
窗口添加通过
IWindowSession
的addView
接口完成。添加时,App 需向 WMS 提供IWindow
接口,使 WMS 能通过该接口通知 App 窗口状态的变化。
从上图可以看出,App(client端)和WMS(Server端)双向通信通道建立完成。
三、窗口添加完整流程
- 以 addView 添加 View 为例
addToDisplayAsUser通过bind调用到WMS完成了窗口的添加。
-
Dialog 和 Activity 的窗口添加
Dialog 和 Activity 的窗口添加流程稍复杂,二者均对应一个
Window
实例。Window
是对窗口公共属性(如标题、背景、菜单等)的抽象,PhoneWindow
是其具体实现。PhoneWindow
包含核心的DecorView
,而DecorView
正是通过WindowManager.addView
添加的 View。PhoneWindow
调用generateDecor
时,会根据主题和特性加载不同的布局与属性。
WindowManagerImpl.addView
之后的流程与前文 addView
方式一致。
备注:以上代码分析以Android 14代码为准