Android中的ClassLoader

Android中的ClassLoader

1. Android中有哪幾種ClassLoader?它們的作用和區(qū)別是什么?

有PathClassLoader, DexClassLoader, BootClassLoader

PathClassLoader: 用來加載系統(tǒng)類和應(yīng)用程序代碼(具體見PathClassLoader的構(gòu)造方法的注釋),只能本地文件系統(tǒng)上的文件和目錄,而不能是網(wǎng)絡(luò)上的

DexClassLoader: 用來加載dex,jar,apk,可以加載未安裝在應(yīng)用程序上的代碼(DexClassLoader需要提供一個應(yīng)用私有的可寫入的目錄,用來存放被優(yōu)化的classes)(具體可以看DexClassLoader構(gòu)造方法上英文的注釋文檔)

PathClassLoader, DexClassLoader 都是繼承自 BaseDexClassLoader,兩者都是調(diào)用的BaseDexClassLoader的方法

/**
 * Provides a simple {@link ClassLoader} implementation that operates on a list
 * of files and directories in the local file system, but does not attempt to
 * load classes from the network. Android uses this class for its system class
 * loader and for its application class loader(s).
 */
public PathClassLoader(String dexPath, String libraryPath,
            ClassLoader parent) {
        super(dexPath, null, libraryPath, parent);
}
/**
 * A class loader that loads classes from {@code .jar} and {@code .apk} files
 * containing a {@code classes.dex} entry. This can be used to execute code not
 * installed as part of an application.
 *
 * <p>This class loader requires an application-private, writable directory to
 * cache optimized classes. Use {@code Context.getDir(String, int)} to create
 * such a directory: <pre>   {@code
 *   File dexOutputDir = context.getDir("dex", 0);
 * }</pre>
 *
 * <p><strong>Do not cache optimized classes on external storage.</strong>
 * External storage does not provide access controls necessary to protect your
 * application from code injection attacks.
 */
public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}

區(qū)別就在于optimizedDirectory是否為null。具體可以看BaseDexClassLoader的構(gòu)造方法

public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(parent);
        this.originalPath = dexPath;
        this.pathList =
            new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
    }

從這里我們找到了DexPathList類,那么還需要看看DexPathList是干嘛的

public DexPathList(ClassLoader definingContext, String dexPath,
            String libraryPath, File optimizedDirectory) {
       ...
        this.dexElements =
            makeDexElements(splitDexPath(dexPath), optimizedDirectory);
}
/**
     * Makes an array of dex/resource path elements, one per element of
     * the given array.
     */
private static Element[] makeDexElements(ArrayList<File> files,
            File optimizedDirectory) {
        ArrayList<Element> elements = new ArrayList<Element>();
        for (File file : files) {
            ...
            dex = loadDexFile(file, optimizedDirectory);
        }
        return elements.toArray(new Element[elements.size()])
}
private static DexFile loadDexFile(File file, File optimizedDirectory)
            throws IOException {
        if (optimizedDirectory == null) {
            return new DexFile(file);
        } else {
            String optimizedPath = optimizedPathFor(file, optimizedDirectory);
            return DexFile.loadDex(file.getPath(), optimizedPath, 0);
        }
    }
...
/**
     * Opens a DEX file from a given File object. This will usually be a ZIP/JAR
     * file with a "classes.dex" inside.
     *
     * The VM will generate the name of the corresponding file in
     * /data/dalvik-cache and open it, possibly creating or updating
     * it first if system permissions allow.  Don't pass in the name of
     * a file in /data/dalvik-cache, as the named file is expected to be
     * in its original (pre-dexopt) state.
     *
     * @param file
     *            the File object referencing the actual DEX file
     *
     * @throws IOException
     *             if an I/O error occurs, such as the file not being found or
     *             access rights missing for opening it
     */
public DexFile(File file) throws IOException {
        this(file.getPath());
}

DexPathList主要是加載全部的dex文件,內(nèi)部通過dexElements屬性維護(hù)全部的dex
我們還需要看一下DexPathList類的loadDexFile方法,里面有我們關(guān)心的一個參數(shù)optimizedDirectory,optimizedDirectory為null時,構(gòu)造一個DexFile對象,不為null的時候,直接通過DexFile.loadDex(sourcePathName, outputPathName, flag)加載一個DexFile文件
先來看看DexFile.loadDex方法

static public DexFile loadDex(String sourcePathName, String outputPathName,
        int flags) throws IOException {
        return new DexFile(sourcePathName, outputPathName, flags);
}
public DexFile(String fileName) throws IOException {
        mCookie = openDexFile(fileName, null, 0);
        mFileName = fileName;
        guard.open("close");
        //System.out.println("DEX FILE cookie is " + mCookie);
}
private DexFile(String sourceName, String outputName, int flags) throws IOException {
        mCookie = openDexFile(sourceName, outputName, flags);
        mFileName = sourceName;
        guard.open("close");
        //System.out.println("DEX FILE cookie is " + mCookie);
}

本質(zhì)上還是調(diào)用的DexFile的構(gòu)造方法,那么不同之處在哪,在于構(gòu)造方法里面openDexFile傳入的參數(shù)outputName,對于optimizedDirectory為null,傳入的outputName為null,這是為什么呢,因?yàn)镻athClassLoader加載的是已經(jīng)安裝的應(yīng)用,這部分classes已經(jīng)被optimized處理過了,位于/data/dalvik-cache/目錄下,不需要在為outputName指定路徑了,而對于DexClassLoader而言,加載的是沒有安裝過的dex文件,那么是需要將優(yōu)化的classes存儲到應(yīng)用的私有目錄。

BootClassLoader: 繼承的是ClassLoader類,作為PathClassLoader的父類加載器存在(也是Android中類加載器的根節(jié)點(diǎn)),也是一個package級別的類,對外獲取不到

2. 簡述ClassLoader的雙親委托模型

雙親委托模型,classLoader用于將一個class文件加載到虛擬機(jī)中,供程序運(yùn)行時使用,動態(tài)加載。
在加載class的過程中,首先會先判斷父加載器有沒有加載這個類,如果加載了,那么由父加載器返回這個class對象,如果沒有的話,那么就由當(dāng)前的類加載器加載。(父加載器也是按照這個過程來)

這樣做的好處是避免重復(fù)加載class,安全

3. 簡述雙親委托模型在熱修復(fù)領(lǐng)域的應(yīng)用

首先我們需要看一下,在Android中,如何加載一個類,看看ClassLoader的loadClass方法

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
...
c = findClass(name);
...
}

//對于android應(yīng)用程序中加載class的加載器,我們確定無疑就是PathClassLoader,而PathClassLoader繼承自BaseDexClassLoader,BaseDexClassLoader的findClass方法是重寫過的
@Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class clazz = pathList.findClass(name);
        if (clazz == null) {
            throw new ClassNotFoundException(name);
        }
        return clazz;
    }

pathList是什么呢,它的類型是DexPathList,DexPathList有一個成員變量叫做dexElements,維護(hù)了全部的dex文件,而我們要查找的類都是通過遍歷這個dexElements數(shù)組,來獲取到的。

在熱修復(fù)中,我們可以將修復(fù)后的bugFixdex插入到這個dexElements的最前面,那么在查找某一個類A(存在bug的話)的時候,就優(yōu)先從bugFixdex中查找到,并返回,而不會使用dexElements里面原來有問題的類A了,這樣就達(dá)到了修復(fù)bug的問題

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容