Android ClassLoader工作原理学习记录(一)

最近一直在处理客户端动态加载、插件相关的功能,其中的核心便是ClassLoader 类加载器。


不看原理,先看现象

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	int i = 0;
        ClassLoader classLoader = getClassLoader();
        if (classLoader != null) {
            LogUtil.e("classLoader " + i++ + " : " + classLoader.toString());
            while (classLoader.getParent() != null) {
                classLoader = classLoader.getParent();
                LogUtil.e("classLoader " + i++ + " : " + classLoader.toString());
            }
        }
}

得到相关日志:

classLoader 0 : dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/XXX/base.apk"],nativeLibraryDirectories=[/data/app/XXX/lib/arm, /system/fake-libs, /data/app/XXX/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]]
classLoader 1 : java.lang.BootClassLoader@81240c4
从日志中可以发现,有两个个ClassLoader实例,一个是 BootClassLoader(系统启动的时候创建的),另一个是 PathClassLoader(应用启动时创建的,用于加载 “/data/app/XXX/base.apk” 里面的类)。
在 Android 系统启动的时候会创建一个 Boot 类型的 ClassLoader 实例,用于加载一些系统 Framework 层级需要的类,我们的 Android 应用里也需要用到一些系统的类,所以 APP 启动的时候也会把这个 Boot 类型的 ClassLoader 传进来。此外,APP 也有自己的类,这些类保存在 APK 的 dex 文件里面,所以 APP 启动的时候,也会创建一个自己的 ClassLoader 实例,用于加载自己 dex 文件中的类。
所以, 一个运行的App至少拥有两个ClassLoader,那么这两个ClassLoader又是如果运作的呢?
查看Instrumentation源码,

public Activity newActivity(ClassLoader cl, String className,Intent intent) 
		throws InstantiationException, IllegalAccessException,ClassNotFoundException {
	return (Activity)cl.loadClass(className).newInstance();
}
可以发现,在创建Activity实例的过程中,调用到的是ClassLoader的loadClass方法:
public Class<?> loadClass(String className) throws ClassNotFoundException {
        return loadClass(className, false);
}
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
    //先查询当前ClassLoader是否已经加载过
    Class<?> clazz = findLoadedClass(className);

    if (clazz == null) {
        ClassNotFoundException suppressed = null;
        try {
	    //再查询Parent是否加载过
            clazz = parent.loadClass(className, false);
        } catch (ClassNotFoundException e) {
            suppressed = e;
        }

        if (clazz == null) {
            try {
		//如果都没有加载过,再执行findClass方法,加载相关的class
                clazz = findClass(className);
            } catch (ClassNotFoundException e) {
                e.addSuppressed(suppressed);
                throw e;
            }
        }
    }
    return clazz;
}
所以一个类加载器的加载流程为:
1、先查询当前ClassLoader是否加载过 
2、如果没有,再查询Parent是否加载过 
3、如果继承路线上的Loader都没有加载过,则有Child执行加载工作


那Parent与当前Child又是什么关系呢?

protected ClassLoader() {
    this(getSystemClassLoader(), false);
}

protected ClassLoader(ClassLoader parentLoader) {
    this(parentLoader, false);
}

ClassLoader(ClassLoader parentLoader, boolean nullAllowed) {
    if (parentLoader == null && !nullAllowed) {
        throw new NullPointerException("parentLoader == null && !nullAllowed");
    }
    parent = parentLoader;
}
通过源码,可以发现,在创建一个构造器实例的时候,必须传入一个已存在的ClassLoader作为新创建的ClassLoader的ParentLoader;在刚开始的实验中,可以发现,调用PathClassLoader的getParent(),获取到的就是BootClassLoader。
这样,一个App中所有的ClassLoader都被关联起来了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值