摘自:《Android 内核剖析》 作者:柯元旦
ClassLoader 类加载器,其作用是动态装载Class文件。每个ClassLoader在初始化时,必须指定Class文件的路径。
在一般情况下,应用程序不需要创建一个全新的ClassLoader对象,而是使用当前环境已经存在的ClassLoader。因为Java的Runtime环境在初始化时,其内部会创建一个ClassLoader对象用于加载Runtime所需的各种Java类。
每个ClassLoader必须有一个父ClassLoader,在装载Class文件时,子ClassLoader会先请求父ClassLoader 加载该文件,只有当其父ClassLoader找不到Class文件时,子ClassLoader才会继续装载该类,这事一种安全机制。
下面是我写的一个基于后面的DexClassLoader的例子,抽取出来的Java小例子:
IntelliJ IDEA 新建工程:PluginDemo
工程新建完毕,新建类PluginClass.java,代码如下:
public class PluginClass {
public PluginClass() {
System.out.println("plugin is init");
}
public int funtion(int a, int b) {
return a + b;
}
}
新建Demo.java类,代码如下:
public class Demo {
public static void main(String[] args) {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try {
Class<?> clazz = classLoader.loadClass("com.test.PluginClass");
Object obj = clazz.newInstance();
Class[] params = new Class[2];
params[0] = Integer.TYPE;
params[1] = Integer.TYPE;
Method method = obj.getClass().getMethod("funtion", params);
Integer integer = (Integer) method.invoke(obj, 12, 23);
System.out.println("result: " +integer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果输出:
plugin is init
result: 35
DexClassLoader 是集成自 ClassLoader的一个类,集成关系如下:
java.lang.Object
↳ java.lang.ClassLoader
↳ dalvik.system.BaseDexClassLoader
↳ dalvik.system.DexClassLoader
Android 应用程序使用标准的Java编译器编译成Class文件,但最终的APK文件包含的确实dex文件类型。dex文件类型是将所需的所有的Class文件重新打包,优化后的一个新文件。因为要加载这样特殊的Class文件,所以就需要特殊的类装载器,这就是DexClassLoader。
下面是这本书里的DexClassLoader例子:
AndroidStudio新建工程Plugin:
新建类PluginClass,代码如下:
public class PluginClass {
public PluginClass() {
Log.e("tag", "Plugin Class initialized");
}
public int function(int a, int b) {
return a + b;
}
}
manifest中添加代码如下:
...
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="com.n.plugin" />
</intent-filter>
</activity>
...
打好包,安装到手机(不用直接点击运行,这样后面跑宿主程序时,会抛找不到的异常)。
AndroidStudio新建工程Host:
MainActivity中添加代码如下:
private void addPlugin() {
Intent intent = new Intent("com.n.plugin", null);
PackageManager manager = getPackageManager();
List<ResolveInfo> infoList = manager.queryIntentActivities(intent, 0);
if (infoList.isEmpty()) {
return;
}
ResolveInfo info = infoList.get(0);
ActivityInfo activityInfo = info.activityInfo;
// String div = System.getProperty("path.separator"); //多个文件路径之间的分隔符
String packageName = activityInfo.packageName;
String dexPath = activityInfo.applicationInfo.sourceDir;
String dexOutputDir = getApplicationInfo().dataDir;
String libPath = activityInfo.applicationInfo.nativeLibraryDir;
DexClassLoader classLoader = new DexClassLoader(dexPath, dexOutputDir, libPath, getClass().getClassLoader());
try {
// 获取Plugin中资源Id的方法
// Resources res = manager.getResourcesForApplication(packageName);
// int id = res.getIdentifier("version", "string", packageName);
// String version = res.getString(id);
Class<?> clazz = classLoader.loadClass(packageName + ".PluginClass");
Object obj = clazz.newInstance();
Class[] params = new Class[2];
params[0] = Integer.TYPE;
params[1] = Integer.TYPE;
Method method = clazz.getMethod("function", params);
Integer integer = (Integer) method.invoke(obj, 12, 23);
Log.e("tag", "--- 获取的结果是 --->" + integer);
} catch (Exception e) {
e.printStackTrace();
}
}
manifest中添加代码如下:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />