Android窗口管理服务WindowManagerService的简要介绍和学习计划

本文深入探讨Android系统中WindowManagerService如何管理和控制各种类型的窗口,包括Activity窗口、子窗口、壁纸窗口等,确保正确的显示和布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在前一个系列文章中,我们从个体的角度来分析了Android应用程序窗口的实现框架。事实上,如果我们从整体的角度来看,Android应用程序窗口的实现要更复杂,因为它们的类型和作用不同,且会相互影响。在Android系统中,对系统中的所有窗口进行管理是窗口管理服务WindowManagerService的职责。在本文中,我们就将简要介绍WindowManagerService的职能以及制定学习计划。

《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

        我们知道,在Android系统中,同一时刻,只有一个Activity窗口是激活的,但是,对于WindowManagerService服务来说,这并不意味着它每次只需要管理一个Activity窗口,例如,在两个Activity窗口的切换过程中,前后两个Activity窗口实际上都是可见的。即使在只有一个Activity窗口是可见的时候,WindowManagerService服务仍然需要同时管理着多个窗口,这是因为可见的Activity窗口可能还会被设置了壁纸窗口(Wallpaper Winodw)或者弹出了子窗口(Sub Window),以及可能会出现状态栏(Status Bar)以及输入法窗口(Input Method Window),如图1所示。


图1 Activity窗口及其子窗口、壁纸窗口、输入法窗口和状态栏的位置结构

        因此,WindowManagerService服务是不可以假设同一时刻它只需要管理一个窗口的,它需要通过各个窗口在屏幕上的位置以及大小来决定哪些窗口需要显示的以及要显在哪里,这实际上就是要计算出各个窗口的可见区域。

        从前面Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析一文可以知道,SurfaceFlinger服务在渲染整个屏幕的UI的时候,会对各个窗品的可见性进行计算,因此,WindowManagerService服务只要将它所管理的各个窗品的位置以及大小告诉SurfaceFlinger服务,后者可以帮帮它计算出各个窗口的可见区域了。注意,这里,这里所说的窗口位置包括窗口在X、Y和Z轴的位置。

       WindowManagerService服务大致按照以下方式来控制哪些窗口需要显示的以及要显在哪里:

       1. 每一个Activity窗口的大小都等于屏幕的大小,因此,只要对每一个Activity窗口设置一个不同的Z轴位置,然后就可以使得位于最上面的,即当前被激活的Activity窗口,才是可见的。

       2. 每一个子窗口的Z轴位置都比它的父窗口大,但是大小要比父窗口小,这时候Activity窗口及其所弹出的子窗口都可以同时显示出来。

       3. 对于非全屏Activity窗口来说,它会在屏幕的上方留出一块区域,用来显示状态栏。这块留出来的区域称对于屏幕来说,称为装饰区(decoration),而对于Activity窗口来说,称为内容边衬区(Content Inset)。

       4. 输入法窗口只有在需要的时候才会出现,它同样是出现在屏幕的装饰区或者说Activity窗口的内容边衬区的。

       5. 对于壁纸窗口,它出现需要壁纸的Activity窗口的下方,这时候要求Activity窗口是半透明的,这样就可以将它后面的壁纸窗口一同显示出来。

       6. 两个Activity窗口在切换过程,实际上就是前一个窗口显示退出动画而后一个窗口显示开始动画的过程,而在动画的显示过程,窗口的大小会有一个变化的过程,这样就导致前后两个Activity窗口的大小不再都等于屏幕的大小,因而它们就有可能同时都处于可见的状态。事实上,Activity窗口的切换过程是相当复杂的,因为即将要显示的Activity窗口可能还会被设置一个启动窗口(Starting Window)。一个被设置了启动窗口的Activity窗口要等到它的启动窗口显示了之后才可以显示出来。

       从以上六点就可以看出,窗口在X、Y和Z轴的位置及其大小的计算非常重要,它们共同决定了一个窗口是否是整体可见的,还是部分可见的,或者整体不可见的。在Android系统中,WindowManagerService服务是通过一个实现了WindowManagerPolicy接口的策略类来计算一个窗口的位置和大小的。例如,在Phone平台上,这个策略类就是PhoneWindowManager。这样做的好处就是对于不同的平台实现不同的策略类来达到不同的窗口控制模式。

      从上面的描述就可以看出,WindowManagerService服务除了要与Activity窗口所运行在的应用程序进程打交道之外,还需要与SurfaceFlinger服务以及窗口管理策略类PhoneWindowManager交互,如图2所示。


图2 WindowManagerService服务与Activity窗口、SurfaceFlinger服务、PhoneWindowManager策略的关系图

        在前面Android应用程序窗口(Activity)实现框架简要介绍和学习计划的一系列文章中,我们已经分析过应用程序进程与WindowManagerService服务之间的交互过程了,因此,在这一系列文章中,我们就将主要分析WindowManagerService服务的实现,以及它与SurfaceFlinger服务、PhoneWindowManager策略类的交互过程。

        从总体上来看,WindowManagerService服务的实现是相当复杂的,例如,WindowManagerService类的核心成员函数performLayoutAndPlaceSurfacesLockedInner的代码有1200+行,比600-行代码的ViewRoot类的核心成员函数performTraversals还要恐怖。不过,WindowManagerService服务实现的复杂性是在预料之中的,毕竟它要管理的整个系统所有窗口的UI,而在任何一个系统中,窗口管理子系统都是极其复杂的。基于上述理由,采用硬碰硬的方式来分析WindowManagerService服务的实现是以卵击石,因此,这个系列的文章将对WindowManagerService服务进行分拆,然后再逐个击破,这是算法中的分而治之思想是一致的。

        具体来说,我们将按照以下几个情景来分析WindowManagerService服务的实现:

        1. 窗口大小和位置(X轴和Y轴)的计算过程

        2. 窗口的组织方式

        3. 输入法窗口的调整过程

        4. 壁纸窗口的调整过程

        5. 窗口Z轴位置的计算和调整过程

        6. Activity窗口的启动窗口的显示过程

        7. Activity窗口的切换过程

        8. Activity窗口的动画显示过程

        再次地,由于WindowManagerService服务的实现实在是太复杂,因此上述八个情景可能还不足于说明WindowManagerService服务的实现。如果出现这种情况,我们在分析的过程中会进行相应的调整。相信对WindowManagerService服务的实现进行分而治之的分析后,我们就可以对Android系统的UI架构有一个深刻的理解!敬请关注接下来的文章!

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

我开发鸿蒙app,有时候开发工具上会出现这样的错误 Device info:HUAWEI Mate 60 Pro Build info:ALN-AL00 5.0.0.135(SP5C00E135R4P30) Fingerprint:5ff289a6822776675751649da231d1db06f7d7bc15d6ef6b00662af0d1ce64ff Module name:com.shuhua.sport.hm Version:1.0.2 Foreground:Yes Pid:47013 Uid:20020178 Reason:HIT_EMPTY_WARNING syswarning: com.shuhua.sport.hm HIT_EMPTY_WARNING at 20250408140445 DisplayPowerInfo:powerState:AWAKE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DOMAIN:FRAMEWORK STRINGID:HIT_EMPTY_WARNING TIMESTAMP:2025/04/08-14:04:45:546 PID:47013 UID:20020178 PACKAGE_NAME: PROCESS_NAME:com.shuhua.sport.hm ******************************************* start time: 2025/04/08-14:04:45:560 DOMAIN = FRAMEWORK EVENTNAME = HIT_EMPTY_WARNING TIMESTAMP = 2025/04/08-14:04:45:546 PID = 47013 UID = 20020178 TID = 47013 PACKAGE_NAME = PROCESS_NAME = com.shuhua.sport.hm eventLog_action = cmd:w eventLog_interval = 300 MSG = HIT_EMPTY_WARNING occured 3 times in 506 ms, {\"windowId\":407,\"windowName\":\"hm0\",\"resultInfo\":\"fingerId: 0\",\"x\":1178,\"y\":248,\"currentTime\":162379217479000,\"bundleName\":\"com.shuhua.sport.hm\",\"pageInfo\":\"pages/home/portrait/PortraitPage.js\"} don't collect ashmem dmaheap gpumem --------------------------------------------------- start time: 2025/04/08-14:04:45 catcher cmd: hidumper -s WindowManagerService -a -a -------------------------------[ability]------------------------------- ----------------------------------WindowManagerService---------------------------------- -------------------------------------ScreenGroup 0------------------------------------- WindowName DisplayId Pid WinId Type Mode Flag ZOrd Orientation [ x y w h ] [ OffsetX OffsetY ] [ ScaleX ScaleY PivotX PivotY ] SCBScenePanel1 0 2834 5 2109 1 0 100 0 [ 0 0 1260 2720 ] [ 0 0 ] [ 1 1 0.5 0.5 ] BackgroundBlurView2 0 2834 6 2109 1 0 101 0 [ 0 0 1260 2720 ] [ 0
最新发布
04-09
<think>嗯,用户问的是鸿蒙App开发中的HIT_EMPTY_WARNING错误的原因解决方案。我需要先理解这个错误是什么情况下出现的。根据经验,这类错误通常布局或资源文件有关。比如,可能某个控件的内容为空,或者引用了不存在的资源。 首先,用户提到错误发生在Framework域的com.shuhua.sport.hm,这可能是一个自定义的包名。我需要检查布局文件中是否有控件没有正确设置内容。例如,Text控件如果没有设置text属性,或者绑定的数据为空,可能会触发这个警告。这时候应该检查对应的XML布局文件,确保所有必要的属性都有值,或者设置默认值。 其次,资源引用问题也可能导致这个错误。比如,图片资源路径错误,或者字符串资源未定义。用户需要检查资源ID是否正确,特别是在使用类似@string或@color的地方。另外,如果资源文件缺失或命名不符合规范,比如包含大写字母或特殊字符,也可能引发问题。这时候应该核对资源文件是否存在,路径是否正确,命名是否符合规范。 还有可能是数据绑定时的空值问题。如果使用了数据绑定框架,当数据源返回null时,控件可能无法正确渲染,导致警告。用户需要确保数据源不为空,或者在绑定表达式中添加空值检查,例如使用三元运算符提供默认值。 另外,日志分析也很重要。查看具体的错误日志,定位到哪个文件哪一行代码触发了错误,这样可以更快地找到问题所在。同时,用户提到参考了引用[2][3],资源文件需要与appid对应,直接替换可能导致问题,所以需要确认资源是否与当前项目的配置匹配。 最后,可能需要检查代码中的线程操作,如引用[4]提到的多线程问题,但不确定是否相关。不过,如果布局是在子线程中更新,也可能导致UI问题,需要确保UI操作在主线程执行。 综合以上可能性,解决方案应该包括检查布局文件、资源引用、数据绑定日志分析,以及确保资源正确配置。可能需要用户逐步排查这些方面,特别是检查最近修改的布局或资源文件,是否有遗漏或错误。</think>### 鸿蒙App开发中HIT_EMPTY_WARNING错误分析与解决方案 #### 错误原因分析 1. **空布局或空组件引用** 当UI布局文件中的组件未正确初始化或绑定了空数据源时,可能触发该警告。例如: ```xml <!-- 错误示例:Text组件未设置text属性 --> <Text ohos:id="$+id:empty_text" ohos:width="match_content" ohos:height="match_content"/> ``` 2. **资源文件缺失或路径错误** 若资源文件(如图片、字符串)未正确关联或命名不规范(如包含大写字母),会导致框架检测到空资源引用[^2][^3]。 3. **数据绑定异常** 使用`DataAbility`或`ViewModel`时,若未正确处理异步数据返回前的空状态,可能引发警告: ```java // 错误示例:未判空直接使用数据 String data = fetchData(); // 可能返回null textComponent.setText(data); // 触发HIT_EMPTY_WARNING ``` #### 具体解决方案 1. **检查布局文件** - 确保所有可显示内容的组件(如`Text`、`Image`)已设置默认值: ```xml <Text ohos:text="$string:default_text" ohos:width="match_content" ohos:height="match_content"/> ``` 2. **验证资源引用** - 核对资源ID与文件名是否匹配,路径是否符合鸿蒙规范: ```json // resources/base/element/string.json { "name": "default_text", "value": "占位文本" } ``` 3. **增强数据健壮性** - 添加空值保护逻辑: ```java String data = fetchData(); textComponent.setText(data != null ? data : getResourceManager().getElement(ResourceTable.String_default_text).getString()); ``` 4. **日志定位** 通过`HiLog`查看详细堆栈信息,定位到具体组件: ```java HiLog.info(LABEL, "HIT_EMPTY_WARNING at %{public}s", Thread.currentThread().getStackTrace()[2].getFileName()); ``` #### 优化建议 - 使用`@State`注解管理组件状态,自动处理空值渲染 - 在`onStart`生命周期中预加载关键资源 - 遵循鸿蒙资源命名规范(全小写+下划线)
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值