zoukankan      html  css  js  c++  java
  • 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 APP里面打开其他应用
    jQuery 中 serialize() 方法会受到asp.net 页面影响
    javascript 对象转换 json 的插件
    MVC 4将jQuery升级到1.9出现各种问题。。。
    用MVC做可拖拽的留言板,利用 Jquery模板 JsRender
    未能加载文件或程序集“Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”
    处理MVC中默认的Json方法返回时间的问题
    jQuery 中使用$.post 无法获取 json
    MVC中用 BundleCollection 压缩CSS时图片路径问题
    MVC中返回Json的几种声明方式
  • 原文地址:https://www.cnblogs.com/dividxiaoshuo-fighting/p/3682398.html
Copyright © 2011-2022 走看看