Android类装载器DexClassLoader的简单使用-----制作android插件的前奏

声明:此篇文章借鉴《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函数。

  

 1 package com.david.plugin;

 2 

 3 import android.util.Log;

 4 

 5 public class Plugin {

 6     

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

 8     

 9     public Plugin(){

10         Log.i(TAG, "PluginClass is initialized");

11     }

12     

13     public int addition(int a,int b){

14         return a+b;

15     }

16     

17 }

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

1 <activity

2             android:name="com.david.plugin.MainActivity"

3             android:label="@string/app_name" >

4             <intent-filter>

5                 <action android:name="com.david.plugin.client"/>

6                 <action android:name="android.intent.action.MAIN" />

7                 <category android:name="android.intent.category.LAUNCHER" />

8             </intent-filter>

9         </activity>

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

 1 package com.david.host;

 2 

 3 import java.lang.reflect.InvocationTargetException;

 4 import java.lang.reflect.Method;

 5 import java.util.List;

 6 

 7 import dalvik.system.DexClassLoader;

 8 import android.support.v7.app.ActionBarActivity;

 9 import android.annotation.SuppressLint;

10 import android.content.Intent;

11 import android.content.pm.ActivityInfo;

12 import android.content.pm.PackageManager;

13 import android.content.pm.ResolveInfo;

14 import android.os.Bundle;

15 import android.view.View;

16 import android.view.View.OnClickListener;

17 import android.widget.Button;

18 

19 

20 public class MainActivity extends ActionBarActivity implements OnClickListener{

21 

22     private static final String plugin_package = "com.david.plugin.client";

23     private PackageManager pm;

24     private ResolveInfo resolveInfo;

25     private Button btn_classLoader;

26 

27     @Override

28     protected void onCreate(Bundle savedInstanceState) {

29         super.onCreate(savedInstanceState);

30         setContentView(R.layout.activity_main);

31 //        useDexClassLoader();

32         btn_classLoader=(Button) findViewById(R.id.btn_classLoader);

33         btn_classLoader.setOnClickListener(this);

34     }

35 

36     @SuppressLint("NewApi")

37     public void useDexClassLoader() {

38         Intent classIntent = new Intent(plugin_package, null);

39         pm = getPackageManager();

40         List<ResolveInfo> activities = pm.queryIntentActivities(classIntent, 0);

41         resolveInfo = activities.get(0);

42         ActivityInfo activityInfo = resolveInfo.activityInfo;

43 

44         String div = System.getProperty("path.separator");

45         String packageName = activityInfo.packageName;

46         String sourceDir = activityInfo.applicationInfo.sourceDir;

47         System.out.println(sourceDir);

48         String outDir = getApplicationInfo().dataDir;

49         System.out.println(outDir);

50         String libraryDir = activityInfo.applicationInfo.nativeLibraryDir;

51         System.out.println(libraryDir);

52 

53         DexClassLoader dexcl = new DexClassLoader(sourceDir, outDir,

54                 libraryDir, this.getClass().getClassLoader());

55         try {

56             Class<?> loadClass = dexcl.loadClass(packageName+".Plugin");

57             Object instance = loadClass.newInstance();

58             Class[] params = new Class[2];

59             params[0]=Integer.TYPE;

60             params[1]=Integer.TYPE;

61             Method method = loadClass.getMethod("addition", params);

62             Integer result = (Integer) method.invoke(instance, 12,32);

63             System.out.println(result);

64         } catch (ClassNotFoundException e) {

65             e.printStackTrace();

66         } catch (InstantiationException e) {

67             e.printStackTrace();

68         } catch (IllegalAccessException e) {

69             e.printStackTrace();

70         } catch (NoSuchMethodException e) {

71             e.printStackTrace();

72         } catch (IllegalArgumentException e) {

73             e.printStackTrace();

74         } catch (InvocationTargetException e) {

75             // TODO Auto-generated catch block

76             e.printStackTrace();

77         } 

78 

79     }

80 

81     @Override

82     public void onClick(View v) {

83         useDexClassLoader();

84     }

85 }

  运行后得到的结果是:

Android类装载器DexClassLoader的简单使用-----制作android插件的前奏

 

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

 

 

 

你可能感兴趣的:(ClassLoader)