一、动态加载简介
在讲解Android的动态加载之前,先给大家脑补一下Java的类加载机制,这样有利于大家对后面的知识的讲解:
1.当我们调用Java命令运行某个Java程序时,该命令将会启动一个Java虚拟机进程,不管该Java程序有多复杂,该程序启动了多少个线程,它们都处于该Java虚拟机进程里;
2.当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过加载、连接、初始化3个步骤来对该类进行初始化;
类加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说,当程序使用任何类时,系统都会为之创建一个java.lang.Class对象;
类连接:负责把类的二进制数据合并到JRE中;
验证:检验被加载的类是否有正确地内部结构,并和其他类协调一致;
准备:为类的静态Field分配内存,并设置默认的初始值;
解析:将类的二进制数据中的符号引用替换成直接引用;
类初始化:负责对类进行初始化,主要就是对静态Field进行初始化;
声明静态Field时指定初始值;
使用静态初始化块为静态Field指定初始值;
3.在Java中,一个类用其全限定类名(包括包名和类名)作为标识,但在JVM中,一个类使用其全限定类名和其加载器作为其唯一标识;
当JVM启动的时候,会形成由3个类加载器组成的初始类加载器层次结构:
Bootstrap ClassLoader:根类加载器,被称为引导(也称为原始或根)类加载器,负载加载Java的核心类;
Extension ClassLoader:扩展类加载器,非常特殊,不是java.lang.Class的子类,由JVM自身实现的,负责加载JRE的扩展目录(%JAVA_HOME%/jre/lib/ex或者和由java.ext.dirs系统属性指定的目录)中JAR包中的类;
System ClassLoader:系统加载器,负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH环境变量所指定的JAR和类路径;
4.JVM类加载机制主要由如下3种:
全盘负责,就是当一个类加载器负责加载某个class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器载入;
父类委托,则是先让parent(父)类加载器视图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类;
缓存机制,将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存中搜寻该Class,只有当缓存区中不存在Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入到缓存区中。
那么,在Android也可以动态加载类,但是无法像Java那样在JVM中方便的使用ClassLoader动态加载Jar。因为Android的虚拟机(Dalvik VM)是不认识Java打出的jar的byte code,需要通过dx工具转换成Dalvik byte code才行。在当前Android中,如下API可以用于动态加载:
1.DexClassLoader:可以加载jar/dex/apk,也可以从SD卡中加载;
2.PatchClassLoader:只能加载已经安装到Android系统中的apk文件;
二、动态加载实践
在Android系统中,DexClassLoader分别支持对dex,未安装apk和已安装apk的动态加载,下面我们就依次进行实践;
1.创建动态加载的类Test.java;
Text.java
在讲解Android的动态加载之前,先给大家脑补一下Java的类加载机制,这样有利于大家对后面的知识的讲解:
1.当我们调用Java命令运行某个Java程序时,该命令将会启动一个Java虚拟机进程,不管该Java程序有多复杂,该程序启动了多少个线程,它们都处于该Java虚拟机进程里;
2.当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过加载、连接、初始化3个步骤来对该类进行初始化;
类加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说,当程序使用任何类时,系统都会为之创建一个java.lang.Class对象;
类连接:负责把类的二进制数据合并到JRE中;
验证:检验被加载的类是否有正确地内部结构,并和其他类协调一致;
准备:为类的静态Field分配内存,并设置默认的初始值;
解析:将类的二进制数据中的符号引用替换成直接引用;
类初始化:负责对类进行初始化,主要就是对静态Field进行初始化;
声明静态Field时指定初始值;
使用静态初始化块为静态Field指定初始值;
3.在Java中,一个类用其全限定类名(包括包名和类名)作为标识,但在JVM中,一个类使用其全限定类名和其加载器作为其唯一标识;
当JVM启动的时候,会形成由3个类加载器组成的初始类加载器层次结构:
Bootstrap ClassLoader:根类加载器,被称为引导(也称为原始或根)类加载器,负载加载Java的核心类;
Extension ClassLoader:扩展类加载器,非常特殊,不是java.lang.Class的子类,由JVM自身实现的,负责加载JRE的扩展目录(%JAVA_HOME%/jre/lib/ex或者和由java.ext.dirs系统属性指定的目录)中JAR包中的类;
System ClassLoader:系统加载器,负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH环境变量所指定的JAR和类路径;
4.JVM类加载机制主要由如下3种:
全盘负责,就是当一个类加载器负责加载某个class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器载入;
父类委托,则是先让parent(父)类加载器视图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类;
缓存机制,将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存中搜寻该Class,只有当缓存区中不存在Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入到缓存区中。
那么,在Android也可以动态加载类,但是无法像Java那样在JVM中方便的使用ClassLoader动态加载Jar。因为Android的虚拟机(Dalvik VM)是不认识Java打出的jar的byte code,需要通过dx工具转换成Dalvik byte code才行。在当前Android中,如下API可以用于动态加载:
1.DexClassLoader:可以加载jar/dex/apk,也可以从SD卡中加载;
2.PatchClassLoader:只能加载已经安装到Android系统中的apk文件;
二、动态加载实践
在Android系统中,DexClassLoader分别支持对dex,未安装apk和已安装apk的动态加载,下面我们就依次进行实践;
1.创建动态加载的类Test.java;
Text.java
public class Test {
//动态加载调用方法getText
public String getText() {
return "load dex";
}
}
2.将Test.java-(javac)->Test.class-(jar);
D:\javatest1>javac Test.java
D:\javatest1>jar cvf test.jar Test.class
标明清单(manifest)
增加:Test.cla