上一篇文章我们介绍了如何偷梁换日,用HostBaseActivity去在Activity运行中代理PluginBaseActivity,并让PluginBaseActivity具有Android中Activity组件的生命周期。也同时留了一个问题,插件的资源加载。这篇文章就和大家一起分享下,插件资源加载涉及到的知识点和解决方案。
Activity静态代理之资源加载
在我介绍解决方案前,我们有必要一起了解下Android的资源相关的知识。
Android应用程序主要由两部分内容组成:代码和资源。资源主要指的是与UI相关的图片啊,布局啊,字符串啊等文件。
Android应用程序资源可以分为两大类,分别是assets和res。
assets类资源放在工程根目录的Assets子目录下,这些文件最终会被原装不动地打包在apk文件中。如果我们要在程序中访问这些文件,那么就需要指定文件名来访问。
res资源也比较好理解,上一个Android官网的介绍 Resource Types
Animation Resources
Define pre-determined animations.
Tween animations are saved in res/anim/ and accessed from the R.anim class.
Frame animations are saved in res/drawable/ and accessed from the R.drawable class.
Color State List Resource
Define a color resources that changes based on the View state.
Saved in res/color/ and accessed from the R.color class.
Drawable Resources
Define various graphics with bitmaps or XML.
Saved in res/drawable/ and accessed from the R.drawable class.
Layout Resource
Define the layout for your application UI.
Saved in res/layout/ and accessed from the R.layout class.
Menu Resource
Define the contents of your application menus.
Saved in res/menu/ and accessed from the R.menu class.
String Resources
Define strings, string arrays, and plurals (and include string formatting and styling).
Saved in res/values/ and accessed from the R.string, R.array, and R.plurals classes.
Style Resource
Define the look and format for UI elements.
Saved in res/values/ and accessed from the R.style class.
Font Resources
Define font families and include custom fonts in XML.
Saved in res/font/ and accessed from the R.font class.
More Resource Types
Define values such as booleans, integers, dimensions, colors, and other arrays.
Saved in res/values/ but each accessed from unique R sub-classes (such as R.bool, R.integer, R.dimen, etc.).
在编译打包的过程中,AAPT会把资源文件打包成二进制文件,并对除了assets资源之外所有的资源赋予一个资源ID常量,并且会生成一个资源索引表resources.arsc。
我们熟知的apk文件其实只是一个zip压缩文件,里面有包含全部java类的文件(classes.dex)和全部编译后的资源文件(resources.arsc).
了解了Android中的资源,我们接下来看一下,我们平时到底是如何使用这些资源的呢?
这里就必须要提到两个类,AssetManager和Resources
简单来说,AssetManager用于访问应用原始的asset文件,相对来说是一个封装层次较低的类。而Resources则提供了高封装层次的API用于获取类型数据,
现在我们可以解释上一篇文章末尾提出的问题了,为什么插件里的资源,宿主里无法直接访问呢?很简单,因为宿主apk打包的时候,resources.arsc文件里面并没有插件里面的资源文件ID,也就访问不到插件里面的资源。也就是说,用宿主的AssetManager和Resources实例是get不到插件的资源的。
聪明的小伙伴已经想到了,那既然宿主的AssetManager和Resources实例不行,那我们用插件的的AssetManager和Resources实例不就可以了?!
是的,『静态代理』的另一层含义就是,访问插件资源的时候,用插件的AssetManager和Resources代理宿主的AssetManager和Resources。上代码:
1 | private AssetManager createAssetManager(String dexPath) { |
在HostActivity中,替换对应的方法为插件的AssetManager和Resources
1 | public class HostBaseActivity extends FragmentActivity { |
这下,宿主里可以获取到插件里对应的资源了。不过插件化带来的资源加载的问题远没那么简单。比如说我们知道,Android系统中通过LayoutInflater加载布局会根据view的包名对view进行相应缓存,在app开发中本来是没有任何问题的。但是我们插件开发,加载了多个apk的代码和资源,势必会有可能不同的插件下不同的view恰好有相同的包名,如果统一用默认的LayoutInflater的话,势必会有问题。下一篇,我们结合LayoutInflater缓存机制,介绍一下解决方案。谢谢大家。