ClassLoader 三 Android 类加载
来源:互联网 发布:杭州云计算产业园 编辑:程序博客网 时间:2024/06/08 17:31
一 前言
Android类加载同样遵循jvm虚拟机规范,不同点是class不是被类加载器直接装载,而是先被打包成dex文件,然后交由BaseDexClassLoader来完成类加载。
二 分类
BaseDexClassLoader 包含两个子类
1. DexClassLoader
2. PathClassLoader
下面分别看下对应的源码 :
package dalvik.system;import java.io.File;/** * A class loader that loads classes from {@code .jar} and {@code .apk} files * containing a {@code classes.dex} entry. This can be used to execute code not * installed as part of an application. * * <p>This class loader requires an application-private, writable directory to * cache optimized classes. Use {@code Context.getDir(String, int)} to create * such a directory: <pre> {@code * File dexOutputDir = context.getDir("dex", 0); * }</pre> * * <p><strong>Do not cache optimized classes on external storage.</strong> * External storage does not provide access controls necessary to protect your * application from code injection attacks. */public class DexClassLoader extends BaseDexClassLoader { /** * Creates a {@code DexClassLoader} that finds interpreted and native * code. Interpreted classes are found in a set of DEX files contained * in Jar or APK files. * * <p>The path lists are separated using the character specified by the * {@code path.separator} system property, which defaults to {@code :}. * * @param dexPath the list of jar/apk files containing classes and * resources, delimited by {@code File.pathSeparator}, which * defaults to {@code ":"} on Android * @param optimizedDirectory directory where optimized dex files * should be written; must not be {@code null} * @param libraryPath the list of directories containing native * libraries, delimited by {@code File.pathSeparator}; may be * {@code null} * @param parent the parent class loader */ public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) { super(dexPath, new File(optimizedDirectory), libraryPath, parent); }}
package dalvik.system;/** * Provides a simple {@link ClassLoader} implementation that operates on a list * of files and directories in the local file system, but does not attempt to * load classes from the network. Android uses this class for its system class * loader and for its application class loader(s). */public class PathClassLoader extends BaseDexClassLoader { /** * Creates a {@code PathClassLoader} that operates on a given list of files * and directories. This method is equivalent to calling * {@link #PathClassLoader(String, String, ClassLoader)} with a * {@code null} value for the second argument (see description there). * * @param dexPath the list of jar/apk files containing classes and * resources, delimited by {@code File.pathSeparator}, which * defaults to {@code ":"} on Android * @param parent the parent class loader */ public PathClassLoader(String dexPath, ClassLoader parent) { super(dexPath, null, null, parent); } /** * Creates a {@code PathClassLoader} that operates on two given * lists of files and directories. The entries of the first list * should be one of the following: * * <ul> * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as * well as arbitrary resources. * <li>Raw ".dex" files (not inside a zip file). * </ul> * * The entries of the second list should be directories containing * native library files. * * @param dexPath the list of jar/apk files containing classes and * resources, delimited by {@code File.pathSeparator}, which * defaults to {@code ":"} on Android * @param libraryPath the list of directories containing native * libraries, delimited by {@code File.pathSeparator}; may be * {@code null} * @param parent the parent class loader */ public PathClassLoader(String dexPath, String libraryPath, ClassLoader parent) { super(dexPath, null, libraryPath, parent); }}
从源码对比来看,二者只是在构造函数中传入的参数不同,最终都是通过父类BaseDexClassLoader构造方法完成初始化,代码如下:
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) { super(parent); this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory); }
BaseDexClassLoader构造方法有四个参数:
1. dexPath dex文件存放的路径
2. optimizedDirectory 优化后的dex存放路径
3. libraryPath 动态库的存放路径
4. parent 父亲类加载器
1 3 4都好理解,2相对特别一些,也是PathClassLoader想较DexClassLoader的不同的地方,PathClassLoader传入的optimizedDirectory是null。optimizedDirectory有什么作用呢?先继续跟踪代码看下去
BaseDexClassLoader构造方法里面只执行了一句
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
创建一个DexPathList对象,跟踪这个类
/** * A pair of lists of entries, associated with a {@code ClassLoader}. * One of the lists is a dex/resource path — typically referred * to as a "class path" — list, and the other names directories * containing native code libraries. Class path entries may be any of: * a {@code .jar} or {@code .zip} file containing an optional * top-level {@code classes.dex} file as well as arbitrary resources, * or a plain {@code .dex} file (with no possibility of associated * resources). * * <p>This class also contains methods to use these lists to look up * classes and resources.</p> *//*package*/ final class DexPathList { /** * List of dex/resource (class path) elements. * Should be called pathElements, but the Facebook app uses reflection * to modify 'dexElements' (http://b/7726934). */ private final Element[] dexElements; /** List of native library directories. */ private final File[] nativeLibraryDirectories;
DexPathList提供以下功能:
1. dex/资源元素列表
2. 动态库文件列表
3. 提供了查找类和资源的方法
2 3 相对容易理解,主要看1,对应代码如下:
/** * Makes an array of dex/resource path elements, one per element of * the given array. */ private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions) { ArrayList<Element> elements = new ArrayList<Element>(); /* * Open all files and load the (direct or contained) dex files * up front. */ for (File file : files) { File 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)) { zip = file; try { dex = loadDexFile(file, optimizedDirectory); } 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); } } else if (file.isDirectory()) { // We support directories for looking up resources. // This is only useful for running libcore tests. elements.add(new Element(file, true, null, null)); } else { System.logW("Unknown file type for: " + file); } if ((zip != null) || (dex != null)) { elements.add(new Element(file, false, zip, dex)); } } return elements.toArray(new Element[elements.size()]); }
该方法主要目标是创建一个dexfile,然后转换成element数组。下面来看dexfile的加载
/** * Constructs a {@code DexFile} instance, as appropriate depending * on whether {@code optimizedDirectory} is {@code null}. */ 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); } }
根据optimizedDirectory是否为null,分别创建不同的DexFile对象。
现在回头来看optimizedDirectory的作用。一个apk文件在安卓设备上有两种存在状态,一种是已经安装了,一种是作为普通文件存放在sdcard上面。apk安装以后会在/data/目录生成一些文件,比如:
/data/app 存放了apk文件
/data/data 存放apk运行过程生成的一些缓存文件
/data/dalvik-cache 存放apk里面的dex文件
因此,假如apk已经安装了,那么jvm加载dex的时候无须指定optimizedDirectory,只需要到/data/dalvik-cache来查找就行了,因此这种情况可以使用PathClassLoader。反之,apk没有安装,那么在加载apk文件的时候需要将zip包里面的dex文件解压出来,存放到一个内部目录供后续jvm加载,这也就是optimizedDirectory的存在意义。
三 总结
至此,通过源码跟踪大致了解了android类加载机制的组成。主要是由BaseDexClassLoader来处理,根据apk是否安装到了设备上面又分为两种类加载器:DexClassLoader和PathClassLoader。
后面可以对DexClassLoader进一步学习,看看它是怎么如何在热修复上发挥重要作用的。
- ClassLoader 三 Android 类加载
- Android类加载ClassLoader
- Android使用ClassLoader加载类
- android类加载器ClassLoader
- 三分钟理解ClassLoader类加载机制
- android基础之ClassLoader类加载器
- Android动态加载ClassLoader
- Android之ClassLoader类加载器(MultiDex、动态加载dex)
- 类加载器及反射机制(三)-ClassLoader
- Classloader类加载器
- classloader加载类原理
- 类加载器ClassLoader
- ClassLoader类加载器
- ClassLoader 类加载器
- classLoader 类加载器
- ClassLoader(类加载器)
- 类加载器(ClassLoader)
- ClassLoader类加载器
- 关于GraphicLayer和canvas混用时,graphicLayer的绑定点击事件不生效
- IIS中给网站添加匿名访问用户图文教程
- 清理Java缓存步骤:
- Qt Windows 打包发布 (二)
- Zip包的增量更新机制
- ClassLoader 三 Android 类加载
- 关于集合的一些源码
- 最常用的eclipse快捷键总结
- JavaScript的显示和隐藏
- python 操作符**与*的用法
- 在Win10 Anaconda中安装Tensorflow
- Android装饰者模式学习笔记(2)
- 关于Python中的无参数实现两个参数的值交换
- docker挂载本地目录,实现文件共享