Android類裝載器DexClassLoader的簡單使用

轉自:http://www.cnblogs.com/dividxiaoshuo-fighting/p/3682398.html?utm_source=tuicool


一、裝載器簡介

“類裝載器”(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 }
複製代碼

  運行後得到的結果是:

 

類加載器在應用中還是用到比較多,還可以基於它設計一種“插件”架構。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章