为什么 MyFragment 是由 PathClassLoader 而不是 MyClassLoader 加载的

Why MyFragment is loaded by PathClassLoader not MyClassLoader

我们正在使用自定义 MyClassLoader 扩展 ClassLoader 来替换默认 PathClassLoader,例如:

    Context mBase = (Context) getFieldValue(application, "mBase");
    Object mPackageInfo = getFieldValue(mBase, "mPackageInfo");
    ORIGINAL_CLASS_LOADER = (ClassLoader) getFieldValue(mPackageInfo, "mClassLoader");
    CUSTOMED_CLASS_LOADER = new MyClassLoader(ORIGINAL_CLASS_LOADER);

在应用程序 onCreat 时执行。

第一个问题是,并不是所有的 classes 都是由 MyClassLoader 加载的,只有 MyActivitysMyViews 是由 MyClassLoader 加载的,MyFragments 仍由 PathClassLoader 加载。这跟上下文有关系吗?

MyClassLoader中我们通过

加载class
    public Class<?> loadClass(String className)
            throws ClassNotFoundException {
        try {
            ClassLoader myDexClassLoader = loaders.get("DEX");
            if(myDexClassLoader != null){
                Class<?> c = null;
                try {
                     c = myDexClassLoader.loadClass(className);
                    // c = loader.findClass(className);
                } catch (ClassNotFoundException e) {
                }
                if (c != null) {
                    return c;
                }
            }
        } 
        return super.loadClass(className);
    }`

myDexClassLoader定义为

    public static class MyDexClassLoader extends DexClassLoader {

    public MyDexClassLoader(String dexPath, String dexOutputDir,
            String libPath, ClassLoader parent) {
        super(dexPath, dexOutputDir, libPath, parent);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        return super.findClass(name);
    }

    @SuppressLint("NewApi")
    @Override
    public Class<?> loadClass(String className)
            throws ClassNotFoundException {
        Class<?> clazz = null;
        try {
            clazz = findClass(className);
        } catch (ClassNotFoundException e) {
        }
        if (clazz != null) {
            return clazz;
        }
        return super.loadClass(className);
    }

}

MyDexClassLoader 由包含 class 的 PatchDex 文件初始化,如 A1C1.

PathClassLoaderMyDexClassLoaderMyClassLoader 的父级。

而在 OriginalApk 中我们有原始的 class A1 B1 C1 .

第二个问题是,我们可以在loadClass方法中打印,new A1是由MyDexClassLoader从PatchDex加载的(由MyClassLoader),

但由于 class B1 不在 PatchDex 中,MyDexClassLoader(为什么不先由 MyClassLoader 调用)最终使用它的父级(PathClassLoader) 加载 old B1,

class B1直接使用C1,所以我们要加载class C1。通过 print loadClass 方法我们发现 MyDexClassLoader 已经取得了控制权,但没有使用它的 PatchDex,只是使用父级的 PathClassLoaderold C1.

这是怎么发生的?为什么 MyDexClassLoader 直接通过它的父级加载 class C1,而不是它的 PatchDex 当它有时?

提前致谢。

andorid 中用于 dex 的 classloader 不同于 java 的 classloader。

例如,pathclassloader 和 dexclassloader 不再引用 child。这些 classloader 有自己的 dex 文件列表,用于从注册的 dex 文件加载 class。

所以,先不要用super class。 必须首先从您自己的自定义 class 加载程序中找到 class。