Android中的类加载器

参考文章

手把手教你实现最简单的插件化框架

Android官方源码

深入理解Android ClassLoader

类的生命周期

类的生命周期可以参看下图

图片

其中,加载阶段可以细分如下

1. 加载类的二进制流

2. 数据结构转换,将二进制流所代表的静态存储结构转化方法区的运行时的数据结构

3. 生成java.lang.Class对象,作为方法区这个类的各种数据的访问入口

加载类的二进制流有以下方法

1. 从zip包中读取,这就发展成了我们常见的JAR、AAR依赖

2. 运行时动态生成,这就是我们常见的动态代理技术,在java.reflect.Proxy中就是用ProxyGenerateProxyClass来为特定的接口生成代理的二进制流

加下来就要详细说下Android的ClassLoader,不过讲之前,需要先介绍下双亲委托机制

双亲委托机制

其实很简单,一句话

先自己的缓存里面找有没有加载过这个类,如果没有,找parent加载,如果parent也没有,就自己加载。

要记住,这里的parent不是父类的意思,不是父类的意思,不是父类的意思。

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // First, check if the class has already been loaded
//先从缓存中加没加载这个类
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {
//从parent中加载
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
//加载不到,就自己加载
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    c = findClass(name);
                }
            }
            return c;
    }

看一下findClass的实现,(BootClassLoader,大部分的ClassLoader的parent都是这个)

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        return Class.classForName(name, false, null);
    }

哈哈,就是我们熟悉的classForName

Android的ClassLoader

是时候祭出这张广为人知的图了。

图片

先挨个介绍一下

  1. ClassLoader是一个抽象类,定义了ClassLoader的主要功能
  2. BootClassLoader是ClassLoader的子类(注意不是内部类,有些材料上说是内部类,是不对的),用于加载一些系统Framework层级需要的类,是Android平台上所有的ClassLoader的最终parent
  3. SecureClassLoader扩展了ClassLoader类,加入了权限方面的功能,加强了安全性
  4. URLClassLoader继承SecureClassLoader,用来通过URI路径从jar文件和文件夹中加载类和资源,在Android中基本无法使用
  5. BaseDexClassLoader是实现了Android ClassLoader的大部分功能
  6. PathClassLoader加载应用程序的类,会加载/data/app目录下的dex文件以及包含dex的apk文件或者java文件(有些材料上说他也会加载系统类,我没有找到,这里存疑
  7. DexClassLoader可以加载自定义dex文件以及包含dex的apk文件或jar文件,支持从SD卡进行加载。我们使用插件化技术的时候会用到
  8. InMemoryDexClassLoader用于加载内存中的dex文件

看下代码

        logcat("Object classLoader:" + Any::class.java.classLoader + ":" + Any::class.java.classLoader?.parent)
        logcat("HomeActivity classLoader:" + HomeActivity::class.java.classLoader + ":" + HomeActivity::class.java.classLoader?.parent)
        logcat("activity classLoader:" + Activity::class.java.classLoader + ":" + Activity::class.java.classLoader?.parent)

日志

2021-02-04 11:36:32.015 3220-3220/com.xxx E/lklog: Object classLoader:java.lang.BootClassLoader@c38876d:null
2021-02-04 11:36:32.015 3220-3220/com.xxx E/lklog: HomeActivity classLoader:dalvik.system.PathClassLoader[DexPathList[[zip file "/system/framework/android.test.mock.jar", zip file "/system/framework/android.test.runner.jar", zip file "/data/app/com.lukouapp-EotfkXsC9iBY-fX92CCqzg==/base.apk"],nativeLibraryDirectories=[/data/app/com.lukouapp-EotfkXsC9iBY-fX92CCqzg==/lib/arm, /data/app/com.lukouapp-EotfkXsC9iBY-fX92CCqzg==/base.apk!/lib/armeabi-v7a, /system/lib, /system/vendor/lib]]]:java.lang.BootClassLoader@c38876d
2021-02-04 11:36:32.015 3220-3220/com.xxx E/lklog: activity classLoader:java.lang.BootClassLoader@c38876d:null

从上面日志可以看到以下信息

1. Any和Activity这类系统类的classloader都是BootClassLoader

2. 自定义类的ClassLoader是PathClassLoader,但parent也是BootClassLoader,并且与上面的ClassLoader是同一个实例

猜你喜欢

转载自blog.csdn.net/weixin_43662090/article/details/113626287