詳解Android中實(shí)現(xiàn)熱更新的原理
這篇文章就來介紹一下Android中實(shí)現(xiàn)熱更新的原理。
一、ClassLoader
我們知道Java在運(yùn)行時(shí)加載對應(yīng)的類是通過ClassLoader來實(shí)現(xiàn)的,ClassLoader本身是一個(gè)抽象來,Android中使用PathClassLoader類作為Android的默認(rèn)的類加載器,PathClassLoader其實(shí)實(shí)現(xiàn)的就是簡單的從文件系統(tǒng)中加載類文件。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的構(gòu)造函數(shù)中new出來的,它的類型是DexPathList??聪翫exPathList.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列表,然后通過調(diào)用element.dexFile對象上的loadClassBinaryName方法來加載類,如果返回值不是null,就表示加載類成功,會(huì)將這個(gè)Class對象返回。而dexElements對象是在DexPathList類的構(gòu)造函數(shù)中完成初始化的。
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
makeDexElements所做的事情就是遍歷我們傳遞來的dexPath,然后一次加載每個(gè)dex文件。
二、實(shí)現(xiàn)
上面分析了Android中的類的加載的流程,可以看出來DexPathList對象中的dexElements列表是類加載的一個(gè)核心,一個(gè)類如果能被成功加載,那么它的dex一定會(huì)出現(xiàn)在dexElements所對應(yīng)的dex文件中,并且dexElements中出現(xiàn)的順序也很重要,在dexElements前面出現(xiàn)的dex會(huì)被優(yōu)先加載,一旦Class被加載成功,就會(huì)立即返回,也就是說,我們的如果想做hotpatch,一定要保證我們的hotpacth dex文件出現(xiàn)在dexElements列表的前面。
要實(shí)現(xiàn)熱更新,就需要我們在運(yùn)行時(shí)去更改PathClassLoader.pathList.dexElements,由于這些屬性都是private的,因此需要通過反射來修改。另外,構(gòu)造我們自己的dex文件所對應(yīng)的dexElements數(shù)組的時(shí)候,我們也可以采取一個(gè)比較取巧的方式,就是通過構(gòu)造一個(gè)DexClassLoader對象來加載我們的dex文件,并且調(diào)用一次dexClassLoader.loadClass(dummyClassName);
方法,這樣,dexClassLoader.pathList.dexElements中,就會(huì)包含我們的dex,通過把dexClassLoader.pathList.dexElements插入到系統(tǒng)默認(rèn)的classLoader.pathList.dexElements列表前面,就可以讓系統(tǒng)優(yōu)先加載我們的dex中的類,從而可以實(shí)現(xiàn)熱更新了。
下面展示一部分代碼
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中實(shí)現(xiàn)熱更新的原理先為大家介紹到這,大家可以結(jié)合平時(shí)積累的知識,查閱相關(guān)書籍進(jìn)行深入學(xué)習(xí)探究,希望大家能夠有所收獲。
- C#實(shí)現(xiàn)在線更新軟件
- 采用C#實(shí)現(xiàn)軟件自動(dòng)更新的方法
- Android 軟件自動(dòng)更新功能實(shí)現(xiàn)的方法
- 非常實(shí)用的小功能 Android應(yīng)用版本的更新實(shí)例
- Android使用Handler和Message更新UI
- Android利用Intent讀取和更新通訊錄
- Android應(yīng)用自動(dòng)更新功能實(shí)現(xiàn)的方法
- Android異步更新UI的四種方式
- 解決Android SDK下載和更新失敗的方法詳解
- Android軟件自動(dòng)更新實(shí)現(xiàn)代碼
相關(guān)文章
Android中imageview.ScaleType使用方法詳細(xì)介紹
這篇文章主要介紹了Android中imageview.ScaleType使用方法詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android自定義控件通用驗(yàn)證碼輸入框的實(shí)現(xiàn)
這篇文章主要介紹了Android自定義控件通用驗(yàn)證碼輸入框的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
Android中BaseActivity自定義標(biāo)題欄
這篇文章主要介紹了Android中BaseActivity自定義標(biāo)題欄,非常實(shí)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
Android藍(lán)牙服務(wù)啟動(dòng)流程分析探索
這篇文章主要介紹了Android藍(lán)牙服務(wù)啟動(dòng)流程,了解內(nèi)部原理是為了幫助我們做擴(kuò)展,同時(shí)也是驗(yàn)證了一個(gè)人的學(xué)習(xí)能力,如果你想讓自己的職業(yè)道路更上一層樓,這些底層的東西你是必須要會(huì)的2023-01-01
一文讀懂Android?Kotlin的數(shù)據(jù)流
這篇文章主要介紹了一文讀懂Android?Kotlin的數(shù)據(jù)流,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-07-07
Android的APK應(yīng)用簽名機(jī)制以及讀取簽名的方法
這篇文章主要介紹了Android的APK應(yīng)用簽名機(jī)制以及讀取簽名的方法,這里作者推薦使用Java自帶的API進(jìn)行APK簽名的讀取,需要的朋友可以參考下2016-02-02
Android Fragment滑動(dòng)組件ViewPager的實(shí)例詳解
這篇文章主要介紹了Android Fragment滑動(dòng)組件ViewPager的實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05

