前言
在上篇Android ClassLoader浅析中我们分析了安卓ClassLoader
和热更新的原理,这篇我们在上篇热更新分析的基础上写个简单的demo实践一下。
概述
我们先回顾下热更新的原理
PathClassLoader
是安卓中默认的类加载器,加载类是通过findClass()
方法,而这个方法最终是通过遍历DexPathList
中的Element[]
数组加载我们需要的类,那么要想实现热更新只需要在出问题的类还没加载前,把补丁的Element
插入到数组前面,这样加载的时候就会优先加载已经修复的类,从而实现了bug的修复。
原理知道了再来屡一下实现思路。
- 通过
DexClassLoader
加载补丁,然后通过反射拿到生成的Element[]
数组。 - 拿到安卓中默认的类加载器
PathClassLoader
,然后通过反射拿到Element[]
数组。 - 将补丁
Element[]
和系统的Element[]
数组合并(补丁元素放在合并数组前面),并重新赋值给PathClassLoader
。
Show Code
在showcode之前我们还有个重要的事情要做就是贴出类加载中相关的源码,因为等会反射会用到。DexClassLoader
和PathClassLoader
只是调用了BaseDexClassLoader
构造方法这里就不贴了。
public class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent, boolean isTrusted) {
super(parent);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
return c;
}
}
final class DexPathList {
private Element[] dexElements;
DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext, isTrusted);
}
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays