Android開發中,咱們經常遇到熱更新這個概念,而這個熱更新具體是怎麼實現的呢?今天在網上看到一個大神分享的熱更新相關實現原理和實現代碼,感受灰常不錯,分享給廣大碼農盆友look look 。html
ClassLoaderandroid
Android的基礎語言是Java,而Java在運行時加載對應的類是經過ClassLoader來實現的,ClassLoader自己是一個抽象來,Android中使用PathClassLoader類做爲Android的默認的類加載器。數組
PathClassLoader又是什麼?PathClassLoader其實實現的就是簡單的從文件系統中加載類文件。PathClassLoade自己繼承自BaseDexClassLoader,BaseDexClassLoader重寫了findClass方法,該方法是ClassLoader的核心,具體代碼以下:ide
@Override函數
protected Class<?> findClass(String name) throws ClassNotFoundException {this
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();spa
Class c = pathList.findClass(name, suppressedExceptions);設計
if (c == null) {htm
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<Throwable> 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, "<-- injectAboveEqualApiLevel14 End.");
return true;
}
以上就是熱更新相關原理及實現代碼,但願能幫助你們更好的掌握這部分知識~~若是還有不清楚的地方,也能夠直接去官網上面查看一下相關文檔。
相關文章:《Android UI設計的基本元素有哪些》