声明:此篇文章借鉴《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. public class MainActivity extends ActionBarActivity implements OnClickListener{
  20.  
  21. private static final String plugin_package = "com.david.plugin.client";
  22. private PackageManager pm;
  23. private ResolveInfo resolveInfo;
  24. private Button btn_classLoader;
  25.  
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState) {
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.activity_main);
  30. // useDexClassLoader();
  31. btn_classLoader=(Button) findViewById(R.id.btn_classLoader);
  32. btn_classLoader.setOnClickListener(this);
  33. }
  34.  
  35. @SuppressLint("NewApi")
  36. public void useDexClassLoader() {
  37. Intent classIntent = new Intent(plugin_package, null);
  38. pm = getPackageManager();
  39. List<ResolveInfo> activities = pm.queryIntentActivities(classIntent, 0);
  40. resolveInfo = activities.get(0);
  41. ActivityInfo activityInfo = resolveInfo.activityInfo;
  42.  
  43. String div = System.getProperty("path.separator");
  44. String packageName = activityInfo.packageName;
  45. String sourceDir = activityInfo.applicationInfo.sourceDir;
  46. System.out.println(sourceDir);
  47. String outDir = getApplicationInfo().dataDir;
  48. System.out.println(outDir);
  49. String libraryDir = activityInfo.applicationInfo.nativeLibraryDir;
  50. System.out.println(libraryDir);
  51.  
  52. DexClassLoader dexcl = new DexClassLoader(sourceDir, outDir,
  53. libraryDir, this.getClass().getClassLoader());
  54. try {
  55. Class<?> loadClass = dexcl.loadClass(packageName+".Plugin");
  56. Object instance = loadClass.newInstance();
  57. Class[] params = new Class[2];
  58. params[0]=Integer.TYPE;
  59. params[1]=Integer.TYPE;
  60. Method method = loadClass.getMethod("addition", params);
  61. Integer result = (Integer) method.invoke(instance, 12,32);
  62. System.out.println(result);
  63. } catch (ClassNotFoundException e) {
  64. e.printStackTrace();
  65. } catch (InstantiationException e) {
  66. e.printStackTrace();
  67. } catch (IllegalAccessException e) {
  68. e.printStackTrace();
  69. } catch (NoSuchMethodException e) {
  70. e.printStackTrace();
  71. } catch (IllegalArgumentException e) {
  72. e.printStackTrace();
  73. } catch (InvocationTargetException e) {
  74. // TODO Auto-generated catch block
  75. e.printStackTrace();
  76. }
  77.  
  78. }
  79.  
  80. @Override
  81. public void onClick(View v) {
  82. useDexClassLoader();
  83. }
  84. }

  运行后得到的结果是:

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

Android类装载器DexClassLoader的简单使用-----制作android插件的前奏的更多相关文章

  1. Android中SharedPerforences的简单使用示例 --Android基础

    SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态,Activity暂停时,将此activity的状态保存到SharedP ...

  2. Android系列:res之shape制作

    大家好,pls call me francis. nice to me you. 本文将介绍使用在Android中使用shape标签绘制drawable资源图片. 下面的代码是shap标签的基本使用情 ...

  3. 基于Android平台的图书管理系统的制作(1)

    在学习了郭神的第一行代码前半段之后,想通过一次实践来完成对已学知识的巩固.于是码下了这个图书管理系统客户端. IDE Android studio,语言 JAVA.XML: 在刚开始设计的时候对于这个 ...

  4. Xamarin.Android之Spinner的简单探讨

    一.前言 今天用了一下Spinner这个控件,主要是结合官网的例子来用的,不过官网的是把数据写在Strings.xml中的, 某种程度上,不是很符合我们需要的,比较多的应该都是从数据库读出来,绑定上去 ...

  5. Xamarin.Android之封装个简单的网络请求类

    一.前言 回忆到上篇 <Xamarin.Android再体验之简单的登录Demo> 做登录时,用的是GET的请求,还用的是同步, 于是现在将其简单的改写,做了个简单的封装,包含基于Http ...

  6. [电子书] 《Android编程入门很简单》

    <Android编程入门很简单>是一本与众不同的Android学习读物,是一本化繁为简,把抽象问题具体化,把复杂问题简单化的书.本书避免出现云山雾罩.晦涩难懂的讲解,代之以轻松活泼.由浅入 ...

  7. android复习第一天-----简单的android常识

    前言:要去面试了,这些天花一些事件把android中简单的知识点来串联的复习一下 1,android中的工程结构 src文件夹:存储android文件的源代码 gen文件夹:有工具自动生成,不要去修改 ...

  8. GitHub 上排名前 100 的 Android 开源库进行简单的介绍

    若有任何疑问可通过邮件或微博联系我 项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开 ...

  9. [原创]Android中LocationManager的简单使用,获取当前位置

    Android中LocationManager的提供了一系列方法来地理位置相关的问题,包括查询上一个已知位置:注册/注销来自某个 LocationProvider的周期性的位置更新:以及注册/注销接近 ...

随机推荐

  1. js判断第二个日期比第一个日期大

    如何用脚本判断用户输入的的字符串是下面的时间格式2004-11-21 必须要保证用户的输入是此格式,并且是时间,比如说月份不大于12等等,另外我需要用户输入两个,并且后一个要比前一个晚,只允许用JAV ...

  2. JSP复习(part 3 )

    3.4.4 request对象提供了一些用来获取客户信息的方法,利用这些方法,可以获取客户端的IP地址 协议等有关信息 3.5 request对象和response对象相对应,用于响应客户请求,由服务 ...

  3. 必备 .NET - C# 脚本

    作者:Mark Michaelis | 2016 年 1 月 Link: https://msdn.microsoft.com/zh-cn/magazine/mt614271.aspx 随着 Visu ...

  4. Pandas数据规整

    Pandas数据规整 数据分析和建模方面的大量编程工作都是用在数据准备上的,有时候存放在文件或数据库中的数据并不能满足数据处理应用的要求 Pandas提供了一组高级的.灵活的.高效的核心函数和算法,它 ...

  5. Python iter() 函数

    Python iter() 函数  Python 内置函数 描述 iter() 函数用来生成迭代器. 语法 以下是 iter() 方法的语法: iter(object[, sentinel]) 参数 ...

  6. Sorting(好题)

    Sorting https://www.zhixincode.com/contest/21/problem/I?problem_id=324 题目描述 你有一个数列a_1, a_2, \dots, a ...

  7. 利用python实现冒泡排序

    1.先生存一个随机数组成的list 2.然后进行排序,把大的元素放在后面,小的元素放在前面,最终实现从小到大排列 首先生存一个随机数组成的list import random # print(sys. ...

  8. day3:vcp考试

    Q41. An administrator creates a custom ESXi firewall rule using an XML file, however the rules do no ...

  9. sign和token设计

    签名设计 对于敏感的api接口,需使用https协议 https是在http超文本传输协议加入SSL层,它在网络间通信是加密的,所以需要加密证书. https协议需要ca证书,一般需要交费. 签名的设 ...

  10. JAVA知识积累 给HttpClient添加Socks代理

    本文描述http client使用socks代理过程中需要注意的几个方面:1,socks5支持用户密码授权:2,支持https:3,支持让代理服务器解析DNS: 使用代理创建Socket 从原理上来看 ...