当前位置: 移动技术网 > IT编程>移动开发>Android > 详解Android中实现热更新的原理

详解Android中实现热更新的原理

2019年07月24日  | 移动技术网IT编程  | 我要评论

泰妍事件,山西王家岭煤矿透水事故,ut165量产工具

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

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

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

}

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网