Android中的ClassLoader
Android中的ClassLoader
Java中的ClassLoader
可以加载jar
包和class
文件,在Android则不同。在Android中,不论DVM还是ART,加载的都是dex
文件。Android中的ClassLoader
可以分为系统类加载器和自定义加载器。
Android中ClassLoader
类继承关系如下
BootClassLoader
BootClassLoader
是ClassLoader
的一个内部类,并继承自ClassLoader
。
它是包内可见的,因此我们没法使用它,也不能使用动态加载。
UrlClassLoader
UrlClassLoader
继承自SecureClassLoader
,它只能用于加载jar文件,但是由于 dalvik 不能直接识别jar,所以在 Android 中无法使用这个加载器。
BaseDexClassLoader
|
|
BaseDexClassLoader
继承自ClassLoader
,用于加载各种dex
中的类。
具体参数的含义
dexPath
. 指目标类所在的APK或jar文件的路径,类装载器将从该路径中寻找指定的目标类,该类必须是APK或jar的全路径.如果要包含多个路径,路径之间必须使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)获得。最终做的是将dexPath路径上的文件ODEX优化到内部位置optimizedDirectory,然后,再进行加载的。optimizedDirectory
. 由于dex文件被包含在APK或者Jar文件中,因此在装载目标类之前需要先从APK或Jar文件中解压出dex文件,该参数就是制定解压出的dex 文件存放的路径。这也是对apk中dex根据平台进行ODEX优化的过程。其实APK是一个程序压缩包,里面包含dex文件,ODEX优化就是把包里面的执行程序提取出来,就变成ODEX文件,因为你提取出来了,系统第一次启动的时候就不用去解压程序压缩包的程序,少了一个解压的过程。这样的话系统启动就加快了。为什么说是第一次呢?是因为DEX版本的也只有第一次会解压执行程序到 /data/dalvik-cache(针对PathClassLoader)或者optimizedDirectory(针对DexClassLoader)目录,之后也是直接读取目录下的的dex文件,所以第二次启动就和正常的差不多了。当然这只是简单的理解,实际生成的ODEX还有一定的优化作用。ClassLoader只能加载内部存储路径中的dex文件,所以这个路径必须为内部路径。librarySearchPath
.指目标类中所使用的C/C++库存放的路径parent
. 是指该装载器的父装载器,一般为当前执行类的装载器,例如在Android中以context.getClassLoader()作为父装载器。
PathClassLoader
|
|
在PathClassLoader
的构造方法中没有参数optimizedDirectory
,这是因为PathClassLoader
已经默认了参数optimizedDirectory
的值为/data/dalvik-cache
目录。所以PathClassLoader
无法定义解压的dex文件的存储路径,因此PathClassLoader
通常用来加载已经安装的apk的dex文件。
DexClassLoader
|
|
DexClassLoader
可以加载dex文件以及包含dex的压缩文件,不管加载哪种文件,最终都是要加载dex文件。
InMemoryDexClassLoader
|
|
InMemoryDexClassLoader
是API26的时候新增的。ByteBuffer数组构造了一个DexPathList,可用于内存中的dex文件。
ClassLoader 的双亲委托模型
|
|
加载类的时候,首先判断有没有加载过,如果已经加载过了直接返回,否则就判断父加载器是否存在。如果存在父加载器,则调用父加载器的loadClass
方法,不存在则调用findBootstrapClassOrNull
方法。但是findBootstrapClassOrNull
会直接返回null
。所以最终又会调用到findClass
方法。而findClass
会直接抛出异常,所以这个需要子类来实现。这就是双亲委托模型。双亲委托模型一方面可以避免重复加载类,另一方面可以避免有人恶意编写一个类加载到JVM中。