詳解Android中實現(xiàn)熱更新的原理
這篇文章就來介紹一下Android中實現(xiàn)熱更新的原理。
一、ClassLoader
我們知道Java在運行時加載對應的類是通過ClassLoader來實現(xiàn)的,ClassLoader本身是一個抽象來,Android中使用PathClassLoader類作為Android的默認的類加載器,PathClassLoader其實實現(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的構造函數(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列表,然后通過調用element.dexFile對象上的loadClassBinaryName方法來加載類,如果返回值不是null,就表示加載類成功,會將這個Class對象返回。而dexElements對象是在DexPathList類的構造函數(shù)中完成初始化的。
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
makeDexElements所做的事情就是遍歷我們傳遞來的dexPath,然后一次加載每個dex文件。
二、實現(xiàn)
上面分析了Android中的類的加載的流程,可以看出來DexPathList對象中的dexElements列表是類加載的一個核心,一個類如果能被成功加載,那么它的dex一定會出現(xiàn)在dexElements所對應的dex文件中,并且dexElements中出現(xiàn)的順序也很重要,在dexElements前面出現(xiàn)的dex會被優(yōu)先加載,一旦Class被加載成功,就會立即返回,也就是說,我們的如果想做hotpatch,一定要保證我們的hotpacth dex文件出現(xiàn)在dexElements列表的前面。
要實現(xiàn)熱更新,就需要我們在運行時去更改PathClassLoader.pathList.dexElements,由于這些屬性都是private的,因此需要通過反射來修改。另外,構造我們自己的dex文件所對應的dexElements數(shù)組的時候,我們也可以采取一個比較取巧的方式,就是通過構造一個DexClassLoader對象來加載我們的dex文件,并且調用一次dexClassLoader.loadClass(dummyClassName);
方法,這樣,dexClassLoader.pathList.dexElements中,就會包含我們的dex,通過把dexClassLoader.pathList.dexElements插入到系統(tǒng)默認的classLoader.pathList.dexElements列表前面,就可以讓系統(tǒng)優(yōu)先加載我們的dex中的類,從而可以實現(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中實現(xiàn)熱更新的原理先為大家介紹到這,大家可以結合平時積累的知識,查閱相關書籍進行深入學習探究,希望大家能夠有所收獲。
相關文章
Android編程實現(xiàn)點擊鏈接打開APP功能示例
這篇文章主要介紹了Android編程實現(xiàn)點擊鏈接打開APP功能,結合實例形式較為詳細的分析了Android實現(xiàn)點擊鏈接打開APP功能的具體步驟與相關注意事項,需要的朋友可以參考下2017-01-01Android中Rxjava實現(xiàn)三級緩存的兩種方式
這篇文章主要介紹了Android中Rxjava實現(xiàn)三級緩存的兩種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04Android+OpenCV4.2.0環(huán)境配置詳解(Android studio)
這篇文章主要介紹了Android+OpenCV4.2.0環(huán)境配置詳解(Android studio),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10Android組件Glide實現(xiàn)圖片平滑滾動效果
這篇文章主要介紹了Android組件Glide實現(xiàn)圖片平滑滾動效果的相關資料,具有一定的參考價值,需要的朋友可以參考下2016-07-07Android編程實現(xiàn)使用handler在子線程中更新UI示例
這篇文章主要介紹了Android編程實現(xiàn)使用handler在子線程中更新UI,涉及Android線程與界面布局相關操作技巧,需要的朋友可以參考下2017-09-09淺談AnDroidDraw+DroidDraw實現(xiàn)Android程序UI設計的分析說明
本篇文章是對AnDroidDraw+DroidDraw實現(xiàn)Android程序UI設計進行了詳細的分析介紹,需要的朋友參考下2013-05-05Android仿英語流利說取詞放大控件的實現(xiàn)方法(附demo源碼下載)
這篇文章主要介紹了Android仿英語流利說取詞放大控件的實現(xiàn)方法,較為詳細的分析了取詞放大控件的實現(xiàn)步驟與相關技巧,需要的朋友可以參考下2016-02-02