[转载]Android类装载器DexClassLoader的简单使用-----制作android插件的前奏 - David小硕 - 博客园

[转载]Android类装载器DexClassLoader的简单使用—–制作android插件的前奏 – David小硕 – 博客园.

声明:此篇文章借鉴《Android内核剖析》整理得来。

一、装载器简介

“类装载器”(ClassLoader),顾名思义,就是用来动态装载class文件的。标准的Java SDK中有个ClassLoader类,借助此类可以装载需要的class文件,前提是

ClassLoader类初始化必须制定class文件的路径。

import关键字引用的类文件和ClassLoader动态加载类的区别:

import引用类的两个特点:1、必须存在于本地,当程序运行该类时,内部类装载器会自动装载该类。

2、编译时必须在现场,否则编译过程会因找不到引用文件而不能正常编译。

classLoader的特点正好于import相反,而且更自由灵活。

每一个ClassLoader必须有一个父ClassLoader,在装载Class文件时,子ClassLoader会先请求其父 ClassLoader加载该文件,只有当其父ClassLoader找不到该文件时,子ClassLoader才会继承装载该类。这是一种安全机制。对 于Android而言,最终的apk文件包含的是dex类型的文件,dex文件是将class文件重新打包,打包的规则又不是简单地压缩,而是完全对 class文件内部的各种函数表,变量表进行优化,产生一个新的文件,即dex文件。因此加载这种特殊的Class文件就需要特殊的类加载器 DexClassLoader。

二、DexClassLoader的方法的实用

假设有两个apk,第一个叫做Host,第二个叫Plugin。Plugin中第一个一个类Plugin,该类中定义了一个addition函数。

package com.david.plugin;

import android.util.Log;

public class Plugin {

private static final String TAG=Plugin.class.getSimpleName();

public Plugin(){
Log.i(TAG, "PluginClass is initialized");
}

public int addition(int a,int b){
return a+b;
}

}

plugin的apk中AndroidManifest文件中,activity必须声明一个action。








将plugin.apk装载进Android设备中。Host.apk中主activity调用的代码如下:

package com.david.host;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import dalvik.system.DexClassLoader;
import android.support.v7.app.ActionBarActivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends ActionBarActivity implements OnClickListener{

private static final String plugin_package = "com.david.plugin.client";
private PackageManager pm;
private ResolveInfo resolveInfo;
private Button btn_classLoader;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// useDexClassLoader();
btn_classLoader=(Button) findViewById(R.id.btn_classLoader);
btn_classLoader.setOnClickListener(this);
}

@SuppressLint("NewApi")
public void useDexClassLoader() {
Intent classIntent = new Intent(plugin_package, null);
pm = getPackageManager();
List activities = pm.queryIntentActivities(classIntent, 0);
resolveInfo = activities.get(0);
ActivityInfo activityInfo = resolveInfo.activityInfo;

String div = System.getProperty("path.separator");
String packageName = activityInfo.packageName;
String sourceDir = activityInfo.applicationInfo.sourceDir;
System.out.println(sourceDir);
String outDir = getApplicationInfo().dataDir;
System.out.println(outDir);
String libraryDir = activityInfo.applicationInfo.nativeLibraryDir;
System.out.println(libraryDir);

DexClassLoader dexcl = new DexClassLoader(sourceDir, outDir,
libraryDir, this.getClass().getClassLoader());
try {
Class<?> loadClass = dexcl.loadClass(packageName+".Plugin");
Object instance = loadClass.newInstance();
Class[] params = new Class[2];
params[0]=Integer.TYPE;
params[1]=Integer.TYPE;
Method method = loadClass.getMethod("addition", params);
Integer result = (Integer) method.invoke(instance, 12,32);
System.out.println(result);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

@Override
public void onClick(View v) {
useDexClassLoader();
}
}

 运行后得到的结果是:

 

类加载器在应用中还是用到比较多,还可以基于它设计一种“插件”架构。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏