android类加载过程,Android类加载机制

ClassLoader

Android 中使用PathClassLoader、DexClassLoader等来实现类的加载,这两个类都继承自BaseDexClassLoader,而BaseDexClassLoader继承自ClassLoader。

从Android官方文档中可知:PathClassLoader用来加载系统类及已安装的应用程序的类;DexClassLoader用来加载jar、apk、dex文件中的类。

ClassLoader使用了一种称为“双亲委托”的机制:

public abstract class ClassLoader {

private final ClassLoader parent;

protected Class> loadClass(String name, boolean resolve)

throws ClassNotFoundException

{

Class c = findLoadedClass(name);

if (c == null) {

try {

if (parent != null) {

c = parent.loadClass(name, false);

} else {

c = findBootstrapClassOrNull(name);

}

} catch (ClassNotFoundException e) {

}

if (c == null) {

c = findClass(name);

}

}

return c;

}

}

调用loadClass方法来加载类时,首先使用findLoadedClass来获取已经被加载到内存中的类,如果类已经加载过,就会直接返回已加载的类;否则,先去调用parent的loadClass方法来加载类,parent无法加载时才会调用自身的findClass方法来加载。

BaseDexClassLoader

public class BaseDexClassLoader extends ClassLoader {

private final DexPathList pathList;

public BaseDexClassLoader(String dexPath, File optimizedDirectory,

String libraryPath, ClassLoader parent) {

super(parent);

this.originalPath = dexPath;

this.pathList =

new DexPathList(this, dexPath, libraryPath, optimizedDirectory);

}

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

Class clazz = pathList.findClass(name);

if (clazz == null) {

throw new ClassNotFoundException(name);

}

return clazz;

}

}

BaseDexClassLoader中findClass方法将类的加载委托给DexPathList类型的pathList处理,下面看下DexPathList

DexPathList

DexPathList类关键方法如下:

final class DexPathList {

private static final String DEX_SUFFIX = ".dex";

private static final String JAR_SUFFIX = ".jar";

private static final String ZIP_SUFFIX = ".zip";

private static final String APK_SUFFIX = ".apk";

private final ClassLoader definingContext;

private final Element[] dexElements;

public DexPathList(ClassLoader definingContext, String dexPath,

String libraryPath, File optimizedDirectory) {

this.definingContext = definingContext;

this.dexElements =

makeDexElements(splitDexPath(dexPath), optimizedDirectory);

}

private static Element[] makeDexElements(ArrayList files,

File optimizedDirectory) {

ArrayList elements = new ArrayList();

for (File file : files) {

ZipFile zip = null;

DexFile dex = null;

String name = file.getName();

if (name.endsWith(DEX_SUFFIX)) {

// Raw dex file (not inside a zip/jar).

try {

dex = loadDexFile(file, optimizedDirectory);

} catch (IOException ex) {

System.logE("Unable to load dex file: " + file, ex);

}

} else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)

|| name.endsWith(ZIP_SUFFIX)) {

try {

zip = new ZipFile(file);

} catch (IOException ex) {

System.logE("Unable to open zip file: " + file, ex);

}

try {

dex = loadDexFile(file, optimizedDirectory);

} catch (IOException ignored) {

}

} else {

System.logW("Unknown file type for: " + file);

}

if ((zip != null) || (dex != null)) {

elements.add(new Element(file, zip, dex));

}

}

return elements.toArray(new Element[elements.size()]);

}

}

DexPathList构造函数参数dexPath包含了dex文件的列表,这些dex文件可以是jar、zip、apk格式的压缩包,也可以直接是dex文件。DexPathList使用makeDexElements方法遍历这些dex文件,使用loadDexFile方法加载dex文件:

final class DexPathList {

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);

}

}

}

loadDexFile方法则使用DexFile的loadDex方法打开dex文件,同时会将dex优化为odex文件,返回的是DexFile对象,对dex文件的打开文件、加载类等操作都通过DexFile来实现。

DexPathList.makeDexElements将每个dex文件对应的File、ZipFile、DexFile包装成Element变量,这些Element变量存在DexPathList的dexElements数组里。

/*package*/ static class Element {

public final File file;

public final ZipFile zipFile;

public final DexFile dexFile;

public Element(File file, ZipFile zipFile, DexFile dexFile) {

this.file = file;

this.zipFile = zipFile;

this.dexFile = dexFile;

}

public URL findResource(String name) {

if ((zipFile == null) || (zipFile.getEntry(name) == null)) {

return null;

}

try {

return new URL("jar:" + file.toURL() + "!/" + name);

} catch (MalformedURLException ex) {

throw new RuntimeException(ex);

}

}

}

DexPathList类里加载class如下:

final class DexPathList {

public Class findClass(String name) {

for (Element element : dexElements) {

DexFile dex = element.dexFile;

if (dex != null) {

Class clazz = dex.loadClassBinaryName(name, definingContext);

if (clazz != null) {

return clazz;

}

}

}

return null;

}

}

DexPathList加载类时,遍历Element数组,使用element.dexFile的loadClassBinaryName方法来实际加载类:

public final class DexFile {

public Class loadClassBinaryName(String name, ClassLoader loader) {

return defineClass(name, loader, mCookie);

}

private native static Class defineClass(String name, ClassLoader loader, int cookie);

}

而loadClassBinaryName方法最终调用的是 native 方法defineClass。

总结

DexClassLoader或PathClassLoader加载类的过程:

DexClassLoader.loadClass ->

DexClassLoader.findClass ->

BaseDexClassLoader.findClass ->

DexPathList.findClass ->

DexFile.loadClassBinaryName ->

DexFile.defineClass

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值