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

相关推荐
阿巴斯甜21 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android