为什么 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
加载的,只有 MyActivitys
和 MyViews
是由 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 文件初始化,如 A1 和 C1.
PathClassLoader
是 MyDexClassLoader
和 MyClassLoader
的父级。
而在 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,只是使用父级的 PathClassLoader
的 old C1.
这是怎么发生的?为什么 MyDexClassLoader
直接通过它的父级加载 class C1,而不是它的 PatchDex 当它有时?
提前致谢。
andorid 中用于 dex 的 classloader 不同于 java 的 classloader。
例如,pathclassloader 和 dexclassloader 不再引用 child。这些 classloader 有自己的 dex 文件列表,用于从注册的 dex 文件加载 class。
所以,先不要用super class。
必须首先从您自己的自定义 class 加载程序中找到 class。
我们正在使用自定义 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
加载的,只有 MyActivitys
和 MyViews
是由 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
由包含 class 的 PatchDex 文件初始化,如 A1 和 C1.
PathClassLoader
是 MyDexClassLoader
和 MyClassLoader
的父级。
而在 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,只是使用父级的 PathClassLoader
的 old C1.
这是怎么发生的?为什么 MyDexClassLoader
直接通过它的父级加载 class C1,而不是它的 PatchDex 当它有时?
提前致谢。
andorid 中用于 dex 的 classloader 不同于 java 的 classloader。
例如,pathclassloader 和 dexclassloader 不再引用 child。这些 classloader 有自己的 dex 文件列表,用于从注册的 dex 文件加载 class。
所以,先不要用super class。 必须首先从您自己的自定义 class 加载程序中找到 class。