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

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

内容简介:在“免安装运行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的方法解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

深入理解OpenCV

深入理解OpenCV

[巴西]Daniel Lelis Baggio / 刘波 / 机械工业出版社 / 2014-9 / 59

opencv是最常见的计算机视觉库之一,它提供了许多经过优化的复杂算法。本书对已掌握基本opencv技术同时想提高计算机视觉的实践经验的开发者来讲是一本非常好的书。每章都有一个单独的项目,其背景也在这些章节中进行了介绍。因此,读者可以依次学习这些项目,也可以直接跳到感兴趣的项目进行学习。 《深入理解opencv:实用计算机视觉项目解析》详细讲解9个实用的计算机视觉项目,通过本书的学习,读者可......一起来看看 《深入理解OpenCV》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具