Android 窗口管理 - 窗口添加过程分析Client端

一、窗口的三种形式

  1. Activity:独立的页面窗口,拥有完整生命周期。这种是最常用的方式。
  2. 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也可以通过这种方式添加浮动窗口。

二、核心接口

  1. 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;
    }
}
  1. 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;
        }
    }
  1. 窗口添加的核心实现

    窗口添加通过 IWindowSessionaddView 接口完成。添加时,App 需向 WMS 提供 IWindow 接口,使 WMS 能通过该接口通知 App 窗口状态的变化。

graph LR subgraph System_Server; WMS; end; subgraph App; View; Activity; Dialog; end; App --IWindowManager--> WMS; App --IWindowSession--> WMS; WMS --IWindow--> View;

从上图可以看出,App(client端)和WMS(Server端)双向通信通道建立完成。

三、窗口添加完整流程

  1. 以 addView 添加 View 为例
sequenceDiagram App->>Context: getSystemService Context->>SystemServiceRegistry:getSystemService: SystemServiceRegistry->>CachedServiceFetcher:getService CachedServiceFetcher->>WindowManagerImpl:new App->>WindowManagerImpl:addView WindowManagerImpl->>WindowManagerGlobal: addView WindowManagerGlobal->>WindowManagerGlobal:getWindowSession WindowManagerGlobal->>ViewRootImpl: new ViewRootImpl() ViewRootImpl->>ViewRootImpl: new IWindow() WindowManagerGlobal->>ViewRootImpl: setView ViewRootImpl->>IWindowSession: addToDisplayAsUser

addToDisplayAsUser通过bind调用到WMS完成了窗口的添加。

  1. Dialog 和 Activity 的窗口添加

    Dialog 和 Activity 的窗口添加流程稍复杂,二者均对应一个 Window 实例。Window 是对窗口公共属性(如标题、背景、菜单等)的抽象,PhoneWindow 是其具体实现。PhoneWindow 包含核心的 DecorView,而 DecorView 正是通过 WindowManager.addView 添加的 View。PhoneWindow 调用 generateDecor 时,会根据主题和特性加载不同的布局与属性。

sequenceDiagram Activity->>Activity: attach Activity->>PhoneWindow: new Activity->>PhoneWindow: setContentView ActivityThread->>Activity: handleResumeActivity Activity->>PhoneWindow: getDectorView PhoneWindow->>PhoneWindow: installDector PhoneWindow->>PhoneWindow: generateDecor Activity->>Activity: makeVisible Activity->>WindowManagerImpl: addView

WindowManagerImpl.addView 之后的流程与前文 addView 方式一致。

备注:以上代码分析以Android 14代码为准

相关推荐
黄林晴33 分钟前
Nearby Connections 重大变更:不再自动开启 Wi-Fi / 蓝牙,适配指南
android
恋猫de小郭1 小时前
Flutter 全新真 3D 实现,用 flutter_scene 能开发一个「我的世界」
android·前端·flutter
HLC++14 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼17 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼18 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon19 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138420 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记20 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难20 小时前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
阿pin1 天前
Android随笔-Retrofit
android·retrofit