Android Classloader

Android 的 Classloader

通过dex字节码来加载,合并多个class文件为一个classe.dex文件。

Android共有三种类加载器:

  • BootClassLoader:父类构造器

  • PathClassLoader:一般是加载指定路径/data/app中的apk,也就是安装到手机中的apk。所以一般作为默认的加载器。

  • DexClassLoader:从包含classes.dex的jar或者apk中,加载类的加载器,可用于动态加载。

PathClassLoaderDexClassLoader源码,都是继承自BaseDexClassLoader

public DexClassLoader(String dexPath, String optimizedDirectory,
      String librarySearchPath, ClassLoader parent) {
    super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}


public class PathClassLoader extends BaseDexClassLoader {

    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);  //见下文
    }
}

public class BaseDexClassLoader extends ClassLoader {
    private final DexPathList pathList;

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

我们可以看到PathClassLoader的两个参数都为null,表明只能接受固定的dex文件,而这个文件是只能在安装后出现的。而DexClassLoaderoptimizedDirectory,和librarySearchPath都是可以自己定义的,说明我们可以传入一个jar或者apk包,保证解压缩后是一个dex文件就可以操作了。因此,我们通常使用DexClassLoader来进行插件化和热修复。

可以看到,BaseDexClassLoader有一个相当重要的过程就是初始化DexPathList。初始化DexPathList的过程主要是收集dexElementsnativeLibraryPathElements。一个Classloader可以包含多个dex文件,每个dex文件被封装到一个Element对象。这element对象在初始化和热修复逻辑中是相当重要的。当查找某个类时,会遍历dexElements,如果找到就返回,否则继续遍历。所以当多个dex中有相同的类,只会加载前面的dex中的类。下面是这段逻辑的具体实现

public Class findClass(String name, List<Throwable> suppressed) {
    for (Element element : dexElements) {
        DexFile dex = element.dexFile;
        if (dex != null) {
            //找到目标类,则直接返回
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }
    return null;
}

转载自

原文地址:https://www.cnblogs.com/huaranmeng/p/13323012.html