IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android类加载器 -> 正文阅读

[移动开发]Android类加载器

Java中类加载器?

1.启动类加载器(Bootstrap ClassLoader):这个类加载器负责放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的类库,用户无法直接使用。

2.扩展类加载器(Extension ClassLoader):这个类加载器由sun.misc.Launcher$AppClassLoader实现。它负责<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。用户可以直接使用。

3.应用程序类加载器(Application ClassLoader):这个类由sun.misc.Launcher$AppClassLoader实现。是ClassLoader中getSystemClassLoader()方法的返回值。它负责用户路径(ClassPath)所指定的类库。用户可以直接使用。如果用户没有自己定义类加载器,默认使用这个。

4.自定义加载器:用户自己定义的类加载器。

双亲委托模式

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,每一层的加载器都采用这种方式,直到委托给顶层的启动类加载器为止,如果超类无法加载该类,则会将类的加载内容退回给它的下一层。

  • 双亲委托模式:可以避免重复加载,能有效的确保一个类的全局唯一性
  • 如果不使用这种委托模式,那我们就可以随时使用自定义的类来动态替代一些核心的类,存在非常大的安全隐患,比如定义 java.lang.String 替代系统的String等操作。

Android中类加载器

Android中包含以下几种ClassLoader

  • BootClassLoader:用来加载Framework层的字节码文件
  • URLClassLoader:加载.jar文件和文件夹中的class,javaWeb等使用,谷歌不用
  • BaseDexClassLoader:PathClassaLoader、DexClassLoader父类
  • PathClassaLoader:加载已经安装到系统中的apk中的class文件
  • DexClassLoader:加载指定目录中的字节码文件(包括aar,apk,jar)

BaseDexClassLoader为核心类,androidStudio中是看不到BaseDexClassLoader源码的,提供下源码查看地址:BaseDexClassLoader.java

BaseDexClassLoader加载过程

1.构造参数

DexClassLoader是BaseDexClassLoader子类,下面分析参数。

/**
 * 构造方法
 */
public class BaseDexClassLoader extends ClassLoader {
    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
                 String librarySearchPath, ClassLoader parent) {
    }
}

/**
 * 构造方法
 */
public class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        super(dexPath, null, librarySearchPath, parent);
    }
}

dexPath:apk/dex/jar文件路径

optimizedDirectory:是odex将dexPath路径中dex优化后的输出路径,这个路径必须是手机内部路劲。此参数已弃用,自API级别26起不再生效。

librarySearchPath:需要加载的C/C++库路径

parent:父加载器(这个比较重要与Android加载class的机制有关)

2.加载过程

BaseDexClassLoader构造方法中传入的参数最终会传给DexPathList,BaseDexClassLoader.findClass最终调用DexPathList.findClass。

/**
 * 构造方法
 */
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent, boolean isTrusted) {
  super(parent);
  //DexPathList
  this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);

  if (reporter != null) {
      reportClassLoaderChain();
  }
}

/**
 * BaseDexClassLoader.findClass
 */
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
  List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
  //DexPathList.findClass
  Class c = pathList.findClass(name, suppressedExceptions);
  if (c == null) {
     ClassNotFoundException cnfe = new ClassNotFoundException(
                    "Didn't find class \"" + name + "\" on path: " + pathList);
     for (Throwable t : suppressedExceptions) {
         cnfe.addSuppressed(t);
     }
     throw cnfe;
  }
  return c;
}
  • DexPathList.findClass最终调用element.findClass,Element[] dexElements是由makeDexElements方法进行赋值。
  • Thinker热修复方案就是将补丁dex插入到dexElements最前端,这样classLoader就会先加载补丁中修复了bug的class文件,由于classLoader双亲委托,再加载原先有bug的class文件时,发现已经有一摸一样的修复了bug的class被加载了,就会直接返回不会再去加载旧class文件,从而完成修复bug的目的。
/**
  * List of dex/resource (class path) elements.
  * Should be called pathElements, but the Facebook app uses reflection
  * to modify 'dexElements' (http://b/7726934).
  */
private Element[] dexElements;

/**
  * DexPathList.findClass
  */
public Class<?> findClass(String name, List<Throwable> suppressed) {
  //dexElements数组
  for (Element element : dexElements) {
       Class<?> clazz = element.findClass(name, definingContext, suppressed);
       if (clazz != null) {
           return clazz;
       }
  }

  if (dexElementsSuppressedExceptions != null) {
      suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
  }
  return null;
}

/**
  * dexElements初始化赋值
  */
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
            List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
  Element[] elements = new Element[files.size()];
  int elementsPos = 0;
  /*
   * Open all files and load the (direct or contained) dex files up front.
   */
  for (File file : files) {
      if (file.isDirectory()) {
          // We support directories for looking up resources. Looking up resources in
          // directories is useful for running libcore tests.
          elements[elementsPos++] = new Element(file);
      } else if (file.isFile()) {
          String name = file.getName();
          DexFile dex = null;
          if (name.endsWith(DEX_SUFFIX)) {
             // Raw dex file (not inside a zip/jar).
             try {
                dex = loadDexFile(file, optimizedDirectory, loader, elements);
                if (dex != null) {
                    elements[elementsPos++] = new Element(dex, null);
                }
             } catch (IOException suppressed) {
                 System.logE("Unable to load dex file: " + file, suppressed);
                 suppressedExceptions.add(suppressed);
             }
          } else {
             try {
                dex = loadDexFile(file, optimizedDirectory, loader, elements);
             } catch (IOException suppressed) {
                  /*
                   * IOException might get thrown "legitimately" by the DexFile constructor if
                   * the zip file turns out to be resource-only (that is, no classes.dex file
                   * in it).
                   * Let dex == null and hang on to the exception to add to the tea-leaves for
                   * when findClass returns null.
                   */
                 suppressedExceptions.add(suppressed);
             }
             if (dex == null) {
                elements[elementsPos++] = new Element(file);
             } else {
                elements[elementsPos++] = new Element(dex, file);
             }
          }
          if (dex != null && isTrusted) {
              dex.setTrusted();
          }
      } else {
         System.logW("ClassLoader referenced unknown path: " + file);
      }
  }    
  if (elementsPos != elements.length) {
          elements = Arrays.copyOf(elements, elementsPos);
  }
  return elements;
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-22 20:43:02  更:2022-02-22 20:44:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 15:53:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码