android loader 作用,Android ClassLoader原理(一)

Android的类加载机制遵循Java的双亲委派原理。其继承关系如下:

ClassLoader

PathClassLoader和DexClassLoader的源码如下:

public class PathClassLoader extends BaseDexClassLoader {

public PathClassLoader(String dexPath, ClassLoader parent) {

super(dexPath, null, null, parent);

}

public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {

super(dexPath, null, librarySearchPath, parent);

}

}

public class DexClassLoader extends BaseDexClassLoader {

public DexClassLoader(String dexPath, String optimizedDirectory,

String librarySearchPath, ClassLoader parent) {

super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);

}

}

public class BaseDexClassLoader extends ClassLoader {

private final DexPathList pathList;

/**

* Constructs an instance.

*

* @param dexPath the list of jar/apk files containing classes and

* resources, delimited by {@code File.pathSeparator}, which

* defaults to {@code ":"} on Android

* @param optimizedDirectory directory where optimized dex files

* should be written; may be {@code null}

* @param librarySearchPath the list of directories containing native

* libraries, delimited by {@code File.pathSeparator}; may be

* {@code null}

* @param parent the parent class loader

*/

public BaseDexClassLoader(String dexPath, File optimizedDirectory,

String librarySearchPath, ClassLoader parent) {

super(parent);

this.pathList = new DexPathList(this, dexPath, librarySearchPath, optimizedDirectory);

}

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

List suppressedExceptions = new ArrayList();

Class c = pathList.findClass(name, suppressedExceptions);

if (c == null) {

ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);

for (Throwable t : suppressedExceptions) {

cnfe.addSuppressed(t);

}

throw cnfe;

}

return c;

}

...

}

PathClassLoader和DexClassLoader的区别仅仅在于构造方法中的optimizedDirectory是否为空,这里先不讨论optimizedDirectory的作用,后续会详细介绍。

从BaseDexClassLoader的源码中可以看出来,加载一个类的时候,都是从pathList(DexPathList的实例)中查找的。DexPathList的findClass()方法源码如下:

public Class findClass(String name, List suppressed) {

//从dexElements数组中查找,dexElements就是用于存储dex文件信息,dexElements在BaseDexClassLoader的构造方法中创建。

for (Element element : dexElements) {

DexFile dex = element.dexFile;

if (dex != null) {

Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);

if (clazz != null) {

return clazz;

}

}

}

if (dexElementsSuppressedExceptions != null) {

suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));

}

return null;

}

DexFile执行了dex文件的class查找工作,其loadClassBinaryName()方法源码如下:

public Class loadClassBinaryName(String name, ClassLoader loader, List suppressed) {

return defineClass(name, loader, mCookie, this, suppressed);

}

private static Class defineClass(String name, ClassLoader loader, Object cookie,

DexFile dexFile, List suppressed) {

Class result = null;

try {

result = defineClassNative(name, loader, cookie, dexFile);

} catch (NoClassDefFoundError e) {

if (suppressed != null) {

suppressed.add(e);

}

} catch (ClassNotFoundException e) {

if (suppressed != null) {

suppressed.add(e);

}

}

return result;

}

其中defineClassNative()方法是一个native方法后面会专门介绍。

Android的ClassLoader加载机制可以总结为一句话:从遍历dexElements数组,挨着查找每个dex文件中是否有待加载打Class文件,如果有,则加载,如果没有,则接着查找下一个dex文件,直到将dexElements数组遍历完毕。很多插件化和热修复技术就是基于这个基本原则来设计。以热修复为例,将待修复的类打包成jar包,在应用启动的时候,将jar包解析成dex文件,并插入到dexElements数组的头部。这样等到待修复的类加载时,永远查找到的是dexElements头部第一个dex文件中的已经修复过的类。热修复的原理就这么简单,当然,热修复的实现方式还有很多,这里不一一说明。基于在dexElements数组头部插入的方式还有一个问题。那就是CLASS_ISPREVERIFIED标记。CLASS_ISPREVERIFIED的问题后面章节会详细说明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值