java:類加載原理:
當類加載器收到加載類或資源的請求時,通常都是先委托給父類加載器加載,也就是說只有當父類加載器找不到指定類或資源時,自身才會執行實際的類加載過程,具體的加載過程如下:
創新互聯是一家集網站建設,江北企業網站建設,江北品牌網站建設,網站定制,江北網站建設報價,網絡營銷,網絡優化,江北網站推廣為一體的創新建站企業,幫助傳統企業提升企業形象加強企業競爭力。可充分滿足這一群體相比中小企業更為豐富、高端、多元的互聯網需求。同時我們時刻保持專業、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們為更多的企業打造出實用型網站。
1、源 ClassLoader 先判斷該 Class 是否已加載,如果已加載,則直接返回 Class,如果沒有則委托給父類加載器。
2、父類加載器判斷是否加載過該 Class,如果已加載,則直接返回 Class,如果沒有則委托給祖父類加載器。
3、依此類推,直到始祖類加載器(引用類加載器)。
4、始祖類加載器判斷是否加載過該 Class,如果已加載,則直接返回 Class,如果沒有則嘗試從其對應的類路徑下尋找 class 字節碼文件并載入。如果載入成功,則直接返回 Class,如果載入失敗,則委托給始祖類加載器的子類加載器。
5、始祖類加載器的子類加載器嘗試從其對應的類路徑下尋找 class 字節碼文件并載入。如果載入成功,則直接返回 Class,如果載入失敗,則委托給始祖類加載器的孫類加載器。
6、依此類推,直到源 ClassLoader。
7、源 ClassLoader 嘗試從其對應的類路徑下尋找 class 字節碼文件并載入。如果載入成功,則直接返回 Class,如果載入失敗,源 ClassLoader 不會再委托其子類加載器,而是拋出異常
Android類加載:
Android中的類加載器是BootClassLoader、PathClassLoader、DexClassLoader,其中BootClassLoader是虛擬機加載系統類需要用到的,PathClassLoader是App加載自身dex文件中的類用到的,DexClassLoader可以加載直接或間接包含dex文件的文件。
PathClassLoader和DexClassLoader都繼承自BaseDexClassLoader,它的一個DexPathList類型的成員變量pathList很重要。DexPathList中有一個Element類型的數組dexElements,這個數組中存放了包含dex文件(對應的是DexFile)的元素。BaseDexClassLoader加載一個類,最后調用的是DexFile的方法進行加載的
下面是代碼熱修復的兩種方式:
1、根據類加載為父委托加載原理 將加載修復后的dex的DexClassLoader插入到PathClassLoader和BootstrapClassLoader中間,也就是將DexClassLoader設置為PathClassLoader的父加載器,將BootstrapClassLoader設置為DexClassLoader 順序為:BootstrapClassLoader--->DexClassLoader--->PathClassLoader
//根據類加載為父委托加載原理 替換有bug的類放在dexPath中讓DexClassLoader優先加載
//類加載順序:BootstrapClassLoader---->DexClassLoader----->PathClassLoader
public void loadPatchDex(Context context, String dexPath, String optimizedDirectory, String librarySearchPath) {
ClassLoader currentClassLoader = context.getClassLoader();//context加載器(PathClassLoader)
ClassLoader parentClassLoader = currentClassLoader.getParent();//context的父加載器(BootstrapClassLoader)
//加載dexPath加載器
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, optimizedDirectory, librarySearchPath, parentClassLoader);
this.setField(ClassLoader.class, this.mParentFieldName, currentClassLoader, dexClassLoader);//設置當前類加載器的父加載器為dexClassLoader
}
/**
* @param clazz
* @param fieldName 屬性名稱
* @param target 要設置屬性的對象
* @param value 設置屬性的值
* @return 設置成功
*/
private boolean setField(Class clazz, String fieldName, Object target, Object value) {
try {
Field field = clazz.getDeclaredField(fieldName);
if (field != null) {
field.setAccessible(true);
field.set(target, value);
}
return true;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;//設置失敗
}
2、根據安卓的PathClassLoader加載機制將DexClassLoader加載的新的Dex添加的DexPathList的dexElements屬性列表中,將更新的dex加載放在dexElements列表索引之前
public void loadPatchDex2(Context context, String dexPath, String optimizedDirectory, String librarySearchPath) {
ClassLoader pathClassLoader = context.getClassLoader();
//加載dexPath加載器
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, optimizedDirectory, librarySearchPath, pathClassLoader.getParent());
//獲取BaseDexClassLoader的DexPathList屬性 私有的需要通過反射獲取
Object dexPathList1 = this.getFieldValue(BaseDexClassLoader.class, this.mDexPathListFieldName, pathClassLoader);//pathClassLoader的PathList屬性
Object dexPathList2 = this.getFieldValue(BaseDexClassLoader.class, this.mDexPathListFieldName, dexClassLoader);
if (dexPathList1 != null && dexPathList2 != null) {
//獲取對應pathList中的dexElements屬性
Object dexElements1 = this.getFieldValue(dexPathList1.getClass(), this.mElementFieldName, dexPathList1);//當前PathClassLoader中的Element[]屬性
Object dexElements2 = this.getFieldValue(dexPathList2.getClass(), this.mElementFieldName, dexPathList2);//DexClassLoader中的Element[]屬性
if (dexElements1 != null && dexElements2 != null) {
//將兩個Element[]屬性合并
Object finalElements = combineArray(dexElements2, dexElements1);
//將合并的值設置給當前的pathClassLoader的Element[]中
this.setField(dexPathList1.getClass(), this.mElementFieldName, dexPathList1, finalElements);
Log.e("HotFixEngine", "loadPatchDex2: success");
}
}
}
/**
* 獲取對應屬性值
* @param clazz
* @param fieldName 屬性名稱
* @param target 要操作的對象
* @return
*/
private Object getFieldValue(Class clazz, String fieldName, Object target) {
Field field = this.getField(clazz, fieldName);
if (field != null) {
try {
field.setAccessible(true);
return field.get(target);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return null;
}
private Field getField(Class clazz, String fieldName) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
/**
* 兩個數組合并
*
* @param arrayLhs
* @param arrayRhs
* @return
*/
private static Object combineArray(Object arrayLhs, Object arrayRhs) {
Class<?> localClass = arrayLhs.getClass().getComponentType();
int i = Array.getLength(arrayLhs);
int j = i + Array.getLength(arrayRhs);
Object result = Array.newInstance(localClass, j);
for (int k = 0; k < j; ++k) {
if (k < i) {
Array.set(result, k, Array.get(arrayLhs, k));
} else {
Array.set(result, k, Array.get(arrayRhs, k - i));
}
}
return result;
}
Demo地址:https://github.com/xuguohongai/android/tree/master/AndroidHotFixDemo
名稱欄目:Android代碼熱修復詳解
標題網址:http://m.newbst.com/article38/gpiipp.html
成都網站建設公司_創新互聯,為您提供網站設計、搜索引擎優化、網站制作、網頁設計公司、網站內鏈、網站排名
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯