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代码为准

相关推荐
oMcLin14 小时前
如何在Ubuntu 22.04 LTS上配置并优化MySQL 8.0分区表,提高大规模数据集查询的效率与性能?
android·mysql·ubuntu
幸福的达哥15 小时前
安卓APP代码覆盖率测试方案
android·代码覆盖率
佛系打工仔15 小时前
绘制K线入门
android
川石课堂软件测试16 小时前
Android和iOS APP平台测试的区别
android·数据库·ios·oracle·单元测试·测试用例·cocoa
花卷HJ17 小时前
Android 通用 BaseDialog 实现:支持 ViewBinding + 全屏布局 + 加载弹窗
android
生产队队长17 小时前
Linux:awk进行行列转换操作
android·linux·运维
叶羽西17 小时前
Android15 EVS HAL中使用Camera HAL Provider接口
android
2501_9159184117 小时前
除了 Perfdog,如何在 Windows 环境中完成 iOS App 的性能测试工作
android·ios·小程序·https·uni-app·iphone·webview
泓博17 小时前
Android状态栏文字图标设置失效
android·composer
叶羽西18 小时前
Android15系统中(娱乐框架和车机框架)中对摄像头的朝向是怎么定义的
android