Shadow解决插件和宿主有同名View的方法解析

栏目: Android · 发布时间: 5年前

内容简介:在“免安装运行App”这个场景中,插件代码通常和宿主是完全不相关的。甚至项目都是独立管理的,插件和宿主是不同团队开发,不同版本发布管理的。在这种情况下,插件和宿主中出现相同名字的类是非常常见的。只要设计好ClassLoader的结构,将插件和宿主的ClassLoader隔离开,就可以避免Java层面的类冲突问题。但是,Android系统中存在一个错误的设计,导致LayoutInflater在inflate的时候使用的View类并不是简单的从ClassLoader中读取的,而是自行做了一层缓存,以View的类

在“免安装运行App”这个场景中,插件代码通常和宿主是完全不相关的。甚至项目都是独立管理的,插件和宿主是不同团队开发,不同版本发布管理的。在这种情况下,插件和宿主中出现相同名字的类是非常常见的。只要设计好ClassLoader的结构,将插件和宿主的ClassLoader隔离开,就可以避免 Java 层面的类冲突问题。但是,Android系统中存在一个错误的设计,导致LayoutInflater在inflate的时候使用的View类并不是简单的从ClassLoader中读取的,而是自行做了一层缓存,以View的类名作为Key保存了Class对象。这个缓存存储在一个静态域上,因此在同一个进程中,不能存在两个同名的View都使用LayoutInflater构造。这个问题常见于插件框架对于support包中的RecycleView支持上。不管这个问题的话,当宿主和插件都使用了support包中的RecycleView,就会出现提示信息类似于“RecycleView cannot cast to RecycleView”的Crash异常。

传统的解决方案

方法一,逃避法。我见过一些插件框架,在宿主和插件都用到support包时,就将插件用的support包去掉,让插件直接使用宿主的support包。这样做可以避免前面例子中使用RecycleView等support包中的View的问题。但是既不能避免其他宿主和插件中重名的自定义View的问题,也使得插件使用的support包版本和预期的不一致了。

方法二,清空缓存法。还有一些插件框架,通过反射修改LayoutInflater的缓存,清空缓存达到目的。这样做有两个问题,一是宿主随时可能再次inflate view,再次写入缓存。插件框架可能要频繁清空缓存,甚至每次使用LayoutInflater前都要清空缓存。这样做会使得LayoutInflater失去缓存机制,造成性能下降。二是通过反射修改这个缓存是不安全的,需要兼容多种版本的Android系统,还会涉及访问系统私有API。

Shadow的解决方案

在开发Shadow的时候,我们仔细学习了LayoutInflater的设计。发现通过LayoutInflater自带的设计就可以解决这个问题。

LayoutInflater是可以继承重写的,而且插件中用到的LayoutInflater都是由插件框架中间层提供的Context返回的,因此我们可以让插件中拿到的所有LayoutInflater都是我们自定义的LayoutInflater。

LayoutInflater具有一个注入Factory的设计,如果设置了LayoutInflater的Factory,LayoutInflater在构造View时就会先试图让注入的Factory构造。如果Factory能够构造出来,就会优先使用。如果构造不出来,才会走内置的构造逻辑。而我们前面说的问题就是内置的构造逻辑造成的。因此,我们就写了一个自定义的Factory,然后复制了原本内置构造逻辑的代码。在这段逻辑中,也有缓存机制。但是我们将缓存的Key添加了标记插件apk的“partKey”作为一部分,这样相同名字的View在缓存中就是不同的Key了。因此,我们既保留了LayoutInflater原本的缓存设计,还让它支持了多插件。所以在Shadow中,不管是宿主和插件,还是多插件之间,都可以使用相同名字的View。

这里还有一个小的知识点,就是一个LayoutInflater对象只能set一次Factory。把我们自定义的Factory设置进去了,插件的代码拿到这个LayoutInflater就不能再次set Factory了。但是LayoutInflater的设计又允许clone一个LayoutInflater对象,保留它的的Factory。当新的LayoutInflater被set Factory时,一个内置的逻辑会将两个Factory合并起来使用。因此在Shadow的代码中,可以看到ShadowLayoutInflater中包含了一个InnerInflater,套了两层LayoutInflater,就是这个原因。

这部分相关代码可以查看 com.tencent.shadow.core.runtime.ShadowFactory2 类和相关类的实现。

PS

最新版本的Android系统已经没有这个Bug了。为了兼容低版本的Android系统,这个问题还是需要解决的。

github.com/Tencent/Sha…

欢迎大家参与到Shadow的开发中来,Shadow的代码有非常多值得优化的地方,让我们开源共建起来!


以上所述就是小编给大家介绍的《Shadow解决插件和宿主有同名View的方法解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

电商产品经理宝典:电商后台系统产品逻辑全解析

电商产品经理宝典:电商后台系统产品逻辑全解析

刘志远 / 电子工业出版社 / 2017-10-1 / 49.00元

时至今日,对于产品经理的要求趋向业务型、平台型,甚至产生了细分领域专家。纯粹的前端产品经理(页面、交互)逐渐失去竞争力。而当后台产品经理的视野开始从功能延伸到模块,再延伸到子系统,最后关注整体系统时,就有了把控平台型产品的能力。 《电商产品经理宝典:电商后台系统产品逻辑全解析》围绕“电商后台产品”,从电商的整体产品架构入手,逐步剖析各支撑子系统。通过学习电商产品后台的架构和逻辑,可以让读者从......一起来看看 《电商产品经理宝典:电商后台系统产品逻辑全解析》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具