本文基于singwhatiwanna的开源DL插件框架讲述,修改并重构了一些内容,任总的blog原理讲得比较浅,这里我基于自己的理解再详细讲一点东西,也算是一个记录吧~
加载Class文件到JVM,以供程序使用的。我们知道,java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的。既然ClassLoader是用来加载类到JVM中的,那么ClassLoader又是如何被加载呢?难道它不是java的类?没有错,在这里确实有一个ClassLoader不是用java语言所编写的,而是JVM实现的一部分,这个ClassLoader就是bootstrapclassloader(启动类加载器),这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求,其中就包括用户定义的ClassLoader,这里所谓的用户定义是指通过java程序实现的ClassLoader,一个是ExtClassLoader,这个ClassLoader是用来加载java的扩展API的,也就是/lib/ext中的类,一个是AppClassLoader,这个ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoader进行加载。当运行一个程序的时候,JVM启动,运行bootstrapclassloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。文字太多,下面列个list供大家参考:
1.bootstrapclassLoader(启动类加载器),加载java核心API,包括用户自定义的classLoader以及另外两个核心classLoader;
2.ExtClassLoader,加载java扩展API,也就是/lib/ext中的类;
3.AppClassLoader,加载程序员自定义类,也就是我们工程classPath下设置的class。
1.当运行一个程序的时候,JVM启动;
2.运行bootstrapclassloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载);
3.调用ExtClassLoader加载扩展API;
4.最后AppClassLoader加载CLASSPATH目录下定义的Class。
Android开发和普通的java开发不同的地方是把class文件再重新打包成dex类型的文件,这种重新打包会对Class文件内部的各种函数表、变量表等进行优化。dex文件是一种经过android打包工具优化后的Class文件,因此加载这样特殊的Class文件就需要特殊的类装载器,所以android中提供了DexClassLoader类。加载流程如下:
1. 通过PacageMangager获得指定的apk的安装的目录,dex的解压缩目录,c/c++库的目录
2.创建一个 DexClassLoader实例
3.加载指定的类返回一个Class
4. 然后使用反射调用这个Class
应用程序的每一个Activity组件都关联有一个ContextImpl对象,这个ContextImpl对象就是用来描述Activity组件的运行上下文环境的。Activity组件是从Context类继承下来的,而ContextImpl同样是从Context类继承下来的。我们在Activity组件调用的大部分成员函数都是转发给与它所关联的一个ContextImpl对象的对应的成员函数来处理的,其中就包括用来访问应用程序资源的两个成员函数getResources和getAssets。
ContextImpl类的成员函数getResources返回的是一个Resources对象,有了这个Resources对象之后,我们就可以通过资源ID来访问那些被编译过的应用程序资源了。ContextImpl类的成员函数getAssets返回的是一个AssetManager对象,有了这个AssetManager对象之后,我们就可以通过文件名来访问那些被编译过或者没有被编译过的应用程序资源文件了。事实上,Resources类也是通过AssetManager类来访问那些被编译过的应用程序资源文件的,不过在访问之前,它会先根据资源ID查找得到对应的资源文件名。
Resources类有一个成员函数getAssets,通过它就可以获得保存在Resources类的成员变量mAssets中的AssetManager,例如,ContextImpl类的成员函数getAssets就是通过调用其成员变量mResources所指向的一个Resources对象的成员函数getAssets来获得一个可以用来访问应用程序的非编译资源文件的AssetManager。
我们知道,Android应用程序除了要访问自己的资源之外,还需要访问系统的资源。系统的资源打包在/system/framework/framework-res.apk文件中,它在应用程序进程中是通过一个单独的Resources对象和一个单独的AssetManager对象来管理的。这个单独的Resources对象就保存在Resources类的静态成员变量mSystem中,我们可以通过Resources类的静态成员函数getSystem就可以获得这个Resources对象,而这个单独的AssetManager对象就保存在AssetManager类的静态成员变量sSystem中,我们可以通过AssetManager类的静态成员函数getSystem同样可以获得这个AssetManager对象。
AssetManager类除了在Java层有一个实现之外,在C++层也有一个对应的实现,而Java层的AssetManager类的功能就是通过C++层的AssetManager类来实现的。Java层的每一个AssetManager对象都有一个类型为int的成员变量mObject,它保存的便是在C++层对应的AssetManager对象的地址,因此,通过这个成员变量就可以将Java层的AssetManager对象与C++层的AssetManager对象关联起来。
C++层的AssetManager类有三个重要的成员变量mAssetPaths、mResources和mConfig。其中,mAssetPaths保存的是资源存放目录,mResources指向的是一个资源索引表,而mConfig保存的是设备的本地配置信息,例如屏幕密度和大小、国家地区和语言等等配置信息。有了这三个成员变量之后,C++层的AssetManager类就可以访问应用程序的资源了。
以上知识是理解安卓插件化非常重要的原理知识,因为插件化的本质就是通过安卓的DexClassLoader去加载apk里的类,再通过AssetManager去加载资源文件,这两玩意儿都进入内存之后,我们的宿主就可以通过接口的方式来调用我们的插件类和资源文件了。
pluginClassName 跳转的Plugin中指定的ActivityName,可以传null,则默认时跳转main Activity
1 通过反射获得插件Activity的默认构造函数
2 通过反射new出一个插件并强转成IDXPlugin
3 回调onAttach方法传入Prxoy的引用
4 调用onCreate方法调起插件
通过配置文件可实现直接通过插件名称调用插件
Service的部分和Activity差不多的原理,不再赘述~
最后来一张UML看下类关系:
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/amurocrash/article/details/46965419