RemoteViews最外层布局的玄机

本文讲述了应用在使用RemoteViews时遇到的崩溃问题,源于资源查找机制。当远程apk的资源引用未指定layout_width,且在定制Launcher中使用了错误的root,导致资源ID重排,引发查找失败。最终解决方案是禁止远程布局使用@开头的资源引用。

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

前言

RemoteViews顾名思义就是远程的View,它并不是一个真正的View,而是一个View的描述结构,用来将本进程的View在其他进程中显示,一般使用场景有两种:通知栏和桌面小部件。

最近就遇到了应用使用RemoteViews不当,导致莫名其妙的玄幻问题,最后还得从系统源码的角度,才定位到真正原因。

起因

在一次发版过程中,有测试反馈,某个测试场景下,Launcher会崩溃。崩溃的直接原因是报展开某进程提供的RemoteViews时,布局xml没有指定layout_witdh,“You must supply a layout_width attribute...”:

对应的布局文件,明明指定了layout_witdh:

应用侧一通查,一笔一笔回退版本(需要快速出版本时的惯用操作),发现是一笔毫不相关的改动,引入的问题。但明眼人一看,这笔提交肯定不是真正原因,我们没有应用源码,那从系统侧探寻真正的原因。

深究

其实一个很小的改动就可以避免崩溃,把layout_width中的@dimen改成数值即可,那就是资源查找的问题了。

让我们来看看RemoteViews展开过程中,是如何查找本来位于远程apk的资源文件的。由于BUG比较好复现,直接断点(问题在系统sdk源码,但是运行在Launcher进程中):

RemoteViews的inflate过程中,如果传入了root,其xml的最外层View的layout相关属性,需要由root计算(对应的是本进程的Resource),其中就包含了layout_width、layout_height等。如果xml有引用dimen等资源,也会在本地进程(Launcher)的Resource中查找。

由于系统本身是根据资源id查找资源(不管其名称如何),资源id是自动生成并且进程独立,因此拿着驴唇不对马嘴的id在本地资源中查找时,可能会找到,也可能会找不到,也可能找到但不对(大概率)。

所以一笔看似不相干的改动,导致了资源id的重排,从而导致本身能找到的id(虽然也是个错的)找不到了,或者找到的资源并不是一个合法的数值。

那么这个RemoteViews的root哪里来的呢?为什么走到了root != null的分支?原来,在定制的Launcher的代码中发现,其加载远端布局时,自动创建一个FrameLayout作为root传入:

结案

至此真相大白,于时让对端进程在外层布局禁止使用@开头的引用资源,Launcher修改的话影响比较大(⊙﹏⊙)。

RemoteViews官网并没有提到这些用法细节,在遇到问题时,只能从源码中寻找答案,加上断点辅助,可以快速定位,找到原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值