这篇文章就来介绍一下Android中实现热更新的原理。

一、ClassLoader
我们知道Java在运行时加载对应的类是通过ClassLoader来实现的,ClassLoader本身是一个抽象来,Android中使用PathClassLoader类作为Android的默认的类加载器,PathClassLoader其实实现的就是简单的从文件系统中加载类文件。PathClassLoade本身继承自BaseDexClassLoader,BaseDexClassLoader重写了findClass方法,该方法是ClassLoader的核心。

@Overrideprotected 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;}

看源码可知,BaseDexClassLoader将findClass方法委托给了pathList对象的findClass方法,pathList对象是在BaseDexClassLoader的构造函数中new出来的,它的类型是DexPathList。看下DexPathList.findClass源码是如何做的:

public Class findClass(String name, List suppressed) {  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;}

直接就是遍历dexElements列表,然后通过调用element.dexFile对象上的loadClassBinaryName方法来加载类,如果返回值不是null,就表示加载类成功,会将这个Class对象返回。而dexElements对象是在DexPathList类的构造函数中完成初始化的。

this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
makeDexElements所做的事情就是遍历我们传递来的dexPath,然后一次加载每个dex文件。

二、实现
上面分析了Android中的类的加载的流程,可以看出来DexPathList对象中的dexElements列表是类加载的一个核心,一个类如果能被成功加载,那么它的dex一定会出现在dexElements所对应的dex文件中,并且dexElements中出现的顺序也很重要,在dexElements前面出现的dex会被优先加载,一旦Class被加载成功,就会立即返回,也就是说,我们的如果想做hotpatch,一定要保证我们的hotpacth dex文件出现在dexElements列表的前面。

要实现热更新,就需要我们在运行时去更改PathClassLoader.pathList.dexElements,由于这些属性都是private的,因此需要通过反射来修改。另外,构造我们自己的dex文件所对应的dexElements数组的时候,我们也可以采取一个比较取巧的方式,就是通过构造一个DexClassLoader对象来加载我们的dex文件,并且调用一次dexClassLoader.loadClass(dummyClassName);

方法,这样,dexClassLoader.pathList.dexElements中,就会包含我们的dex,通过把dexClassLoader.pathList.dexElements插入到系统默认的classLoader.pathList.dexElements列表前面,就可以让系统优先加载我们的dex中的类,从而可以实现热更新了。

下面展示一部分代码

private static synchronized Boolean injectAboveEqualApiLevel14(      String dexPath, String defaultDexOptPath, String nativeLibPath, String dummyClassName) {  Log.i(TAG, "--> injectAboveEqualApiLevel14");  PathClassLoader pathClassLoader = (PathClassLoader) DexInjector.class.getClassLoader();  DexClassLoader dexClassLoader = new DexClassLoader(dexPath, defaultDexOptPath, nativeLibPath, pathClassLoader);  try {    dexClassLoader.loadClass(dummyClassName);    Object dexElements = combineArray(        getDexElements(getPathList(pathClassLoader)),        getDexElements(getPathList(dexClassLoader)));    Object pathList = getPathList(pathClassLoader);    setField(pathList, pathList.getClass(), "dexElements", dexElements);  } catch (Throwable e) {    e.printStackTrace();    return false;  }  Log.i(TAG, "

Android中实现热更新的原理先为大家介绍到这,大家可以结合平时积累的知识,查阅相关书籍进行深入学习探究,希望大家能够有所收获。

更多相关文章

  1. Android文件路径
  2. android读写文件函数代码
  3. android menu学习
  4. 基于Android扫描sd卡与系统文件的介绍
  5. Android窗口抖动之动画实现
  6. android java 文件 设置 对应 layout 下 布局文件.xml
  7. android之ArrayAdaper应用
  8. 类和 Json对象
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android 创建socket客户端
  2. Android 禁止ViewPager滑动
  3. 如何区别Android手机卡三大运营商
  4. android需要的访问权限(不断更新,希望大家
  5. Android HelloWorld程序
  6. API 25 (Android 7.1.1 API) animation.A
  7. Android 分别使用Post与Get实现网络图片
  8. android国外网站
  9. android 第三方库使用笔记
  10. mac 彻底删除android studio