总结
作为一名从事Android的开发者,很多人最近都在和我吐槽Android是不是快要凉了?而在我看来这正是市场成熟的表现,所有的市场都是温水煮青蛙,永远会淘汰掉不愿意学习改变,安于现状的那批人,希望所有的人能在大浪淘沙中留下来,因为对于市场的逐渐成熟,平凡并不是我们唯一的答案!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
MultiDex.install(this);
}
}
2、分包配置
分包就创建了一个SecondActivity类
做模拟异常和修复异常的入口,和一个Calculate
模拟异常,做了10/0
的操作,修复后为10/1
注:获取修复后的
classes2.dex
文件可以通过直接buildapk直接解压获取,或者用build-tools下的dx.bat
执行命令获取
简单贴下SecondActivity
,点击fix
按钮后的代码:
private void update() {
//将下载的修复包,复制到私有目录,解压从.dex文件中取到对应的.class文件
//从sd卡取修复包
File sourceFile = new File(Environment.getExternalStorageDirectory(), Constants.DEX_NAME);
//目标文件
File targetFile = new File(getDir(Constants.DEX_DIR, Context.MODE_PRIVATE).getAbsolutePath() + File.separator + Constants.DEX_NAME);
if (targetFile.exists()) {
targetFile.delete();
Log.e(“update”,“删除原有dex文件(已使用的)”);
}
//将SD卡中的修复包copy到私有目录
FileUtils.copyFile(sourceFile,targetFile);
Log.e(“update”,“copy完成”);
FixDexUtils.loadDexFile(this);
}
3、FixModule
新建一个Module处理热修复的相关逻辑
只有五个文件,核心文件代码在FixDexUtils
,其它是工具类,还有个定义了几个常量 看下FixDexUtils
中的代码
public class FixDexUtils {
//修复文件可能有多个
private static HashSet loadedDex = new HashSet<>();
//不建议这么写,demo演示用
static {
loadedDex.clear();
}
public static void loadDexFile(Context context) {
//获取私有目录
File fileDir = context.getDir(Constants.DEX_DIR, Context.MODE_PRIVATE);
//遍历筛选私有目录中的.dex文件
File[] listFiles = fileDir.listFiles();
for (int i = 0; i < listFiles.length; i++) {
//文件名以.dex结尾,且不是主包.dex文件
if (listFiles[i].getName().endsWith(Constants.DEX_SUFFIX) && !“classes.dex”.equalsIgnoreCase(listFiles[i].getName())) {
loadedDex.add(listFiles[i]);
}
}
//创建自定义的类加载器
createDexClassLoader(context ,fileDir);
}
/**
- @param context
- @param fileDir
- 创建自己的类加载器,加载私有目录的.dex文件,上面已经将修复包中的dex文件copy到私有目录
*/
private static void createDexClassLoader(Context context, File fileDir) {
//解压目录
String optimizedDir = fileDir.getAbsolutePath()+File.separator+“opt_dex”;
File fileOpt = new File(optimizedDir);
if (!fileOpt.exists()) {
fileOpt.mkdirs();
}
for (File dex : loadedDex) {
//创建自己的类加载器,临时的
DexClassLoader classLoader = new DexClassLoader(dex.getAbsolutePath(), optimizedDir, null, context.getClassLoader());
//有一个修复文件,就插装一次
hotFix(classLoader,context);
}
}
private static void hotFix(DexClassLoader classLoader, Context context) {
try {
//获取系统的PathClassLoader类加载器
PathClassLoader pathClassLoader = (PathClassLoader)context.getClassLoader();
//获取自己的dexElements数组
Object myElements = ReflectUtils.getDexElements(ReflectUtils.getPathList(classLoader));
//获取系统的dexElements数组
Object systemElements = ReflectUtils.getDexElements(ReflectUtils.getPathList(pathClassLoader));
//合并数组,并排序,生成一个新的数组
Object dexElements=ArrayUtils.combineArray(myElements,systemElements);
//通过反射获取系统的pathList属性
Object systemPathList = ReflectUtils.getPathList(pathClassLoader);
//通过反射,将合并后新的dexElements赋值给系统的pathList
ReflectUtils.setFieldValue(systemPathList,“dexElements”,dexElements);
}catch (Exception e){
e.printStackTrace();
}
}
}
主要做的工作就是:就是上面那张流程图,就是先通过遍历,解压等操作,获取到需要执行热修复的.dex
文件集合,遍历该集合,对应每次创建一个临时的DexClassLoader
,然后执行修复步骤,细分就是六步:
最终实现效果如图(Demo使用手机是华为8.0的手机):
注:这里为了效果图更直观,已经重启过一次app
注: 这种方式实现的热修复必须要重启App才可以实现修复,这一点也是类加载机制决定的,如下图中修复之后再次打开加载执行修复后的classes.dex
文件是在BaseApplication
中调用了修复方法
更多系列教程GitHub白嫖地址:https://github.com/Timdk857/Android-Architecture-knowledge-2-(白嫖可以,标星再走!)
最后
在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!