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

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

(0)

相关推荐

  • Android使用Handler和Message更新UI

    在Android中,在非主线程中更新UI控件是不安全的,app在运行时会直接Crash,所以当我们需要在非主线程中更新UI控件,那么就需要用到Handler和Message来实现 Demo中,使用到一个按钮和一个TextView,点击按钮之后改变TextView的内容,按钮点击时候新建一个进程,在进程中对UI控件进行修改. public class MainActivity extends Activity implements OnClickListener { private static

  • 解决Android SDK下载和更新失败的方法详解

    最近刚换了电脑,开始搭建Android开发环境的时候,下载SDK总是会出现如下错误: 复制代码 代码如下: Failed to fetch URL http://dl-ssl.google.com/android/repository/addons_list-1.xml. 说dl-ssl.google.com在大陆被强了,解决方法就是修改C:\Windows\System32\drivers\etc\hosts文件.添加一行: 复制代码 代码如下: 74.125.237.1       dl-s

  • Android利用Intent读取和更新通讯录

    一.简介 本节演示如何在安卓系统中通过用户配置文件(user profile)读取和更新该手机的所有联系人信息,以及如何导航到用户配置文件中的这些联系人. 二.基本概念  1.什么是 User Profile 用户配置文件(user profile)保存的是机主信息以及该手机中所有联系人的信息. 假定手机所有者的名字为"Mao mao yu",那么,user profile保存的就是"Mao mao yu"的通讯录(即机主所有联系人的姓名.电话.邮箱.--等信息).

  • 非常实用的小功能 Android应用版本的更新实例

    每一个应用都是具备一个功能,那就是版本更新,我记得我之前在面试的时候,面试官让我介绍一下应用版本更新的一些具体操作.我当时因为做过这个功能,所以回答的还是很流畅,现在我把这个分享给大家,需要能够共同进步. 我当时是这么说的: 首先呢,我们是应该在用户登录后,在首页执行检查版本信息的操作,具体是,获取到本地的版本号后,提交给服务器进行判断,然后后台来告诉我们当前版本是否为最新版本,紧接着我们拿到下载地址,执行下载的操作,具体的可以使用输入输出流来对文件进行存储和读取,为了方便下载,我们还可以使用一

  • Android应用自动更新功能实现的方法

    本文给大家分享Android里应用版本更新功能这一块的实现. 一个好的应用软件都是需要好的维护,从初出版本到最后精品,这个过程需要版本不停的更新,那么如何让用户第一时间获取最新的应用安装包呢?那么就要求我们从第一个版本就要实现升级模块这一功能. 自动更新功能的实现原理,就是我们事先和后台协商好一个接口,我们在应用的主Activity里,去访问这个接口,如果需要更新,后台会返回一些数据(比如,提示语:最新版本的url等).然后我们给出提示框,用户点击开始下载,下载完成开始覆盖安装程序,这样用户的应

  • Android 软件自动更新功能实现的方法

    相信所有的用户都遇到过软件提醒更新的情况,下面就将实现此功能 首先看一下程序目录结构    步骤: 1.新建一个类UpdateManger,用于显示提示更新 复制代码 代码如下: public class UpdateManger { // 应用程序Context private Context mContext; // 提示消息 private String updateMsg = "有最新的软件包,请下载!"; // 下载安装包的网络路径 private String apkUrl

  • Android异步更新UI的四种方式

    大家都知道由于性能要求,android要求只能在UI线程中更新UI,要想在其他线程中更新UI,大致有4种方式,下面分别使用四种方式来更新一个TextView. 1.使用Handler消息传递机制 package com.example.runonuithreadtest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.widget.TextView;

  • Android软件自动更新实现代码

    如何实现软件自动更新,下面是具体实例: 效果图: 具体步骤: 1.在服务器上部署更新所用的xml文件:version.xml <update> <version>2</version> <name>baiduxinwen.apk</name> <url>http://gdown.baidu.com/data/wisegame/e5f5c3b8e59401c8/baiduxinwen.apk</url> </updat

  • 采用C#实现软件自动更新的方法

    本文实例分析了采用C#实现软件自动更新的方法,是非常实用的功能,值得学习和借鉴.具体如下: 1.问题概述: 长期以来,广大程序员为到底是使用Client/Server,还是使用Browser/Server结构争论不休,在这些争论当中,C/S结构的程序可 维护性差,布置困难,升级不方便,维护成本高就是一个相当重要的因素.有很多企业用户就是因为这个原因而放弃使用C/S.然而当一个应用必须要使用C/S 结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程

  • C#实现在线更新软件

    通过某些手段后台更新软件.首先你要有一个放置新版本信息的网站 UpdateSoftwareForm.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using CCWin;

随机推荐