【问题标题】:Why MyFragment is loaded by PathClassLoader not MyClassLoader为什么 MyFragment 由 PathClassLoader 而不是 MyClassLoader 加载
【发布时间】:2016-07-15 11:39:17
【问题描述】:

我们正在使用自定义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 时执行。

第一个问题是,并不是所有的类都是由MyClassLoader首先加载的,只是MyActivitysMyViews是由MyClassLoader加载的,MyFragments仍然是由PathClassLoader加载的。这和上下文有关吗?

MyClassLoader我们加载类

    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 使用 PatchDex 文件初始化,其中包含 A1C1 等类。

PathClassLoaderMyDexClassLoaderMyClassLoader 的父级。

在 OriginalApk 我们有原始类 A1 B1 C1

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

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

类 B1 直接使用 C1,所以我们必须加载类 C1。通过 print loadClass 方法我们发现 MyDexClassLoader 已经控制了,但是没有使用它的 PatchDex,只是使用了 parent 的 PathClassLoaderold C1

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

提前致谢。

【问题讨论】:

  • 我忘了还有一个问题,为什么MyClassLoader不是第一个调用的类加载器?有时直接调用MyDexClassLoaderloadClass而不调用MyClassLoaderloadClass

标签: android classloader patch


【解决方案1】:

andorid for dex 中的类加载器与 java 的类加载器不同。

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

所以,不要先使用超类。 必须首先从您自己的自定义类加载器中找到类。

【讨论】:

  • 非常感谢,你拯救了我的一天!我仔细检查了源代码,它是 BaseDexClassLoader 中的private final DexPathList pathList;,所以所有的发现都是找到自己的 DexPathList pathList。
猜你喜欢
  • 2016-02-14
  • 2021-01-28
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-09
  • 1970-01-01
相关资源
最近更新 更多