1. 程式人生 > >Android動態載入入坑指南

Android動態載入入坑指南

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.