# HotReloadSample **Repository Path**: ZhangQQ_123/HotReloadSample ## Basic Information - **Project Name**: HotReloadSample - **Description**: PathClassLoader实现热修复示例 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2020-10-10 - **Last Updated**: 2021-04-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HotReloadSample #### 介绍 PathClassLoader实现热修复 #### 原理 在android中加载我们编写的apk应用中的dex文件中的类,是使用DexClassLoader和PathClassLoader - DexClassLoader:加载未安装过的.jar、.apk、.aar文件 - PathClassLoader:会从已安装的app的安装目录加载dex文件 此示例会用到的类是:PathClassLoader,PathClassLoader的父类BaseDexClassLoader,DexPathList.在BaseDexClassLoader有了DexPathList的引用 ``` public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) { // TODO We should support giving this a library search path maybe. super(parent); this.pathList = new DexPathList(this, dexFiles); } ``` pathList会存放安装的apk的dex文件的描述信息,当我们new一个类的时候,类加载器会调用findClass在dex文件中找这个类,并加载进内存,创建实例 ``` @Override protected Class findClass(String name) throws ClassNotFoundException { List suppressedExceptions = new ArrayList(); //会遍历dex文件寻找需要加载的类 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; } ``` pathList.findClass()会循环遍历dex添加进去的dex文件进行寻找,如果在第一个dex文件中找到了需要的类就把这个类返回,热修复就是把修改过的dex文件的描述信息放到pathList的第一个位置,当类 加载的时候会从修改过的dex文件中找到已修复的类,就不会去加载后面的dex文件中的这个类了 ``` public Class findClass(String name, List suppressed) { for (Element element : dexElements) { //当在第一个dex文件中找到了需要加载的类,就直接返回了 Class clazz = element.findClass(name, definingContext, suppressed); if (clazz != null) { return clazz; } } if (dexElementsSuppressedExceptions != null) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } return null; } ``` - 把class文件编译成dex文件: > dx --dex --output=/Users/zhang/out.dex /Users/zhang/Documents/androidProjects/HotReloadSample/app/build/intermediates/javac/debug/classes 1. 首先把android sdk中Bbuild-tools添加到环境变量中 2. 使用dx --dex --output指令进行编译 3. /Users/zhang/out.dex为输出路径,以空格分隔,后面接着是文件的输入路径/Users/zhang/Documents/androidProjects/HotReloadSample/app/build/intermediates/javac/debug/classes 4. 注意:输入路径不是类名,是完整的包名所在的根目录,例如编译生成的类的class文件完整的路径是:/Users/zhang/Documents/androidProjects/HotReloadSample/app/build/intermediates/javac/debug/classes/com/study/hotreloadsample/HotReload.class那打包dex文件的输入路径就是/Users/zhang/Documents/androidProjects/HotReloadSample/app/build/intermediates/javac/debug/classes