当前位置:   article > 正文

DexClassLoader和PathClassLoader的区别_dexclassloader和patchclassloader

dexclassloader和patchclassloader

 在使用Java虚拟机时,我们经常自定义继承自ClassLoader的类加载器。然后通过defineClass方法来从一个二进制流中加载Class。而在Android中我们无法这么使用,androidClassLoader的defineClass方法具体是调用VMClassLoader的defineClass本地静态方法。而这个本地方法什么都没做,只是抛出了一个“UnsupportedOperationException”异常。 
    既然在Dalvik虚拟机里,ClassLoader不好用,那么Android官方为了解决这个问题,帮我们从ClassLoader中派生出了两个类:DexClassLoader和PathClassLoader。咋一看两者很像,那么究竟二者在使用上面有何不同,这里我和大家一起探讨一下。

首先来看一下二者的构造方法

  1. DexClassLoader
  2. public DexClassLoader (String dexPath, String dexOutputDir, String libPath, ClassLoader parent)
参数详解:

dexPath:dex文件路径列表,多个路径使用”:”分隔 
dexOutputDir:经过优化的dex文件(odex)文件输出目录 
libPath:动态库路径(将被添加到app动态库搜索路径列表中) 
parent:这是一个ClassLoader,这个参数的主要作用是保留java中ClassLoader的委托机制(优先父类加载器加载classes,由上而下的加载机制,防止重复加载类字节码)

DexClassLoader是一个可以从包含classes.dex实体的.jar或.apk文件中加载classes的类加载器。可以用于实现dex的动态加载、代码热更新等等。这个类加载器必须要一个app的私有、可写目录来缓存经过优化的classes(odex文件),使用Context.getDir(String, int)方法可以创建一个这样的目录,例如:

  1. File dexOutputDir = context.getDir(“dex”, 0);
  2. PathClassLoader
  3. PathClassLoader提供两个常用构造方法
  4. public PathClassLoader (String path, ClassLoader parent)
  5. public PathClassLoader (String path, String libPath, ClassLoader parent)

参数详解:

path:文件或者目录的列表 
libPath:包含lib库的目录列表 
parent:父类加载器

PathClassLoader提供一个简单的ClassLoader实现,可以操作在本地文件系统的文件列表或目录中的classes,但不可以从网络中加载classes。

为了便于理解,我们查看一下二者的源码:


  1. // DexClassLoader.javapublic class DexClassLoader extends BaseDexClassLoader {
  2. public DexClassLoader(String dexPath, String optimizedDirectory,
  3. String libraryPath, ClassLoader parent) {
  4. super(dexPath, new File(optimizedDirectory), libraryPath, parent);
  5. }
  6. }
  7. // PathClassLoader.javapublic class PathClassLoader extends BaseDexClassLoader {
  8. public PathClassLoader(String dexPath, ClassLoader parent) {
  9. super(dexPath, null, null, parent);
  10. }
  11. public PathClassLoader(String dexPath, String libraryPath,
  12. ClassLoader parent) {
  13. super(dexPath, null, libraryPath, parent);
  14. }
  15. }



很明显两者都继承于BaseDexClassLoader类,并做了一下封装,具体的实现还是在父类里。不难看出,主要的区别在于PathClassLoader的optimizedDirectory参数只能是null,那么optimizedDirectory是做什么用的呢?我们进BaseDexClassLoader去看看这个参数。

代码中与optimizedDirectory有关的地方是new 一个DexPathList实例。


  1. public BaseDexClassLoader(String dexPath, File optimizedDirectory,
  2. String libraryPath, ClassLoader parent) {
  3. super(parent);
  4. this.originalPath = dexPath;
  5. this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
  6. }
  7. public DexPathList(ClassLoader definingContext, String dexPath,
  8. String libraryPath, File optimizedDirectory) {
  9. ……
  10. this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory);
  11. }
  12. private static Element[] makeDexElements(ArrayList<File> files,
  13. File optimizedDirectory) {
  14. ArrayList<Element> elements = new ArrayList<Element>();
  15. for (File file : files) {
  16. ZipFile zip = null;
  17. DexFile dex = null;
  18. String name = file.getName();
  19. if (name.endsWith(DEX_SUFFIX)) {
  20. dex = loadDexFile(file, optimizedDirectory);
  21. } else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)
  22. || name.endsWith(ZIP_SUFFIX)) {
  23. zip = new ZipFile(file);
  24. }
  25. ……
  26. if ((zip != null) || (dex != null)) {
  27. elements.add(new Element(file, zip, dex));
  28. }
  29. }
  30. return elements.toArray(new Element[elements.size()]);
  31. }
  32. private static DexFile loadDexFile(File file, File optimizedDirectory)
  33. throws IOException {
  34. if (optimizedDirectory == null) {
  35. return new DexFile(file);
  36. } else {
  37. String optimizedPath = optimizedPathFor(file, optimizedDirectory);
  38. return DexFile.loadDex(file.getPath(), optimizedPath, 0);
  39. }
  40. }
  41. /**
  42. * Converts a dex/jar file path and an output directory to an
  43. * output file path for an associated optimized dex file.
  44. */
  45. private static String optimizedPathFor(File path,
  46. File optimizedDirectory) {
  47. String fileName = path.getName();
  48. if (!fileName.endsWith(DEX_SUFFIX)) {
  49. int lastDot = fileName.lastIndexOf(".");
  50. if (lastDot < 0) {
  51. fileName += DEX_SUFFIX;
  52. } else {
  53. StringBuilder sb = new StringBuilder(lastDot + 4);
  54. sb.append(fileName, 0, lastDot);
  55. sb.append(DEX_SUFFIX);
  56. fileName = sb.toString();
  57. }
  58. }
  59. File result = new File(optimizedDirectory, fileName);
  60. return result.getPath();
  61. }


optimizedDirectory是用来缓存我们需要加载的dex文件的,并创建一个DexFile对象,如果它为null,那么会直接使用dex文件原有的路径来创建DexFile 
对象。

optimizedDirectory必须是一个内部存储路径,无论哪种动态加载,加载的可执行文件一定要存放在内部存储。DexClassLoader可以指定自己的optimizedDirectory,所以它可以加载外部的dex,因为这个dex会被复制到内部路径的optimizedDirectory;而PathClassLoader没有optimizedDirectory,所以它只能加载内部的dex,这些大都是存在系统中已经安装过的apk里面的。


通过以上的分析,我们可以得出二者功能上的区别

DexClassLoader:能够加载未安装的jar/apk/dex 
PathClassLoader:只能加载系统中已经安装过的apk

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/796408
推荐阅读
相关标签
  

闽ICP备14008679号