Android動態載入入坑指南
阿新 • • 發佈:2018-12-30
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions,
ClassLoader loader) {
return makeElements(files, optimizedDirectory, suppressedExceptions, false, loader);
}
private static Element[] makeElements(List<File> files, File optimizedDirectory, List<IOException> suppressedExceptions, boolean ignoreDexFiles, ClassLoader loader) { Element[] elements = new Element[files.size()]; int elementsPos = 0; /* * Open all files and load the (direct or contained) dex files * up front. */ for (File file : files) { File zip = null; File dir = new File(""); DexFile dex = null; String path = file.getPath(); String name = file.getName(); if (path.contains(zipSeparator)) { String split[] = path.split(zipSeparator, 2); zip = new File(split[0]); dir = new File(split[1]); } else if (file.isDirectory()) { // We support directories for looking up resources and native libraries. // Looking up resources in directories is useful for running libcore tests. elements[elementsPos++] = new Element(file, true, null, null); } else if (file.isFile()) { if (!ignoreDexFiles && name.endsWith(DEX_SUFFIX)) { // Raw dex file (not inside a zip/jar). try { dex = loadDexFile(file, optimizedDirectory, loader, elements); } catch (IOException suppressed) { System.logE("Unable to load dex file: " + file, suppressed); suppressedExceptions.add(suppressed); } } else { zip = file; if (!ignoreDexFiles) { try { dex = loadDexFile(file, optimizedDirectory, loader, elements); } catch (IOException suppressed) { /* * IOException might get thrown "legitimately" by the DexFile constructor if * the zip file turns out to be resource-only (that is, no classes.dex file * in it). * Let dex == null and hang on to the exception to add to the tea-leaves for * when findClass returns null. */ suppressedExceptions.add(suppressed); } } } } else { System.logW("ClassLoader referenced unknown path: " + file); } if ((zip != null) || (dex != null)) { elements[elementsPos++] = new Element(dir, false, zip, dex); } } if (elementsPos != elements.length) { elements = Arrays.copyOf(elements, elementsPos); } return elements; }
通過程式碼我們可以大致瞭解到,這個方法就是將之前的File物件通過重新組合成一個新的Elements物件,然後我們Loader讀取的就是Element物件。看一下 loadDexFile() 怎樣載入 DexFile 的
private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader, Element[] elements) throws IOException { if (optimizedDirectory == null) { return new DexFile(file, loader, elements); } else { String optimizedPath = optimizedPathFor(file, optimizedDirectory); return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements); } }
先說明下無論是
DexFile(File file, Classloader loader, Elements[] elements)
還是 DexFile.loadDex() 最終都會呼叫 DexFile(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements)
這個構造方法。所以這個方法的邏輯就是:如果 optimizedDirectory
為 null,那麼就直接利用 file 的路徑構造一個 DexFile
;否則就根據要載入的 dex(或者包含了 dex 的 zip) 的檔名和優化後的 dex 存放的目錄組合成優化後的 dex(也就是 odex)檔案的輸出路徑,然後利用原始路徑和優化後的輸出路徑構造出一個DexFile.