您的位置:首页 > 移动开发 > Android开发

Android类加载器

2015-08-03 11:24 351 查看

Android动态加载jar/dex——DexClassLoader类加载器

前言:

像eclipse、chrome浏览器中的插件,这些插件都是为了在一个主程序中实现比较通用的功能,把用户自定义扩展的功能不附加在主程序中,主程序可在运行时安装和卸载。还有在实际项目中,有些因为业务频繁的升级,造成了较差的用户体验,而使用以插件的形式会改善这类弊端。在Android如何实现插件已经被广泛使用,实现原理都是实现一套插件接口,把插件实现编成apk或者dex,然后在运行时使用DexClassLoader动态加载进来,不过在这个开发过程中会遇到一点问题,这里就介绍一下两种使用DexClassLoader来实现插件的功能。

一、概念

1.1 首先需要了解一点:在Android中可以动态加载,但无法像Java中那样方便动态加载

原因:Android的虚拟机(Dalvik VM)是不认识Java打出jar的byte code,需要通过dx工具来优化转换成Dalvik byte code才行。这 一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex。所以这条路不通,请大家注意。

1.2 当前哪些API可用于动态加载

1.2.1  DexClassLoader

这个可以加载jar/apk/dex,也可以从SD卡中加载,也是本文的重点。

      

1.2.3  PathClassLoader

只能加载已经安装到Android系统中的apk文件。

二、实践(两种实现方案)

注意:为了方便,我这里没有写两个工程来测试,两种方案都是在一个工程中完成的!原理都是一样的。

2.1 方案一:(编写接口和实现,通过反射来调用插件程序中的方法)

2.1.1 接口Iinterface
package com.putaolab.dex;
public interface Iinterface
{
public String getData();
}

2.1.2 实现类Iclass
public class Iclass implements Iinterface {
public Context context;

public Iclass(Context context)
{
this.context = context;
}
@Override
public String getData()
{
// TODO Auto-generated method stub
return "hello,i am from the method of getData()...";
}
}

2.1.3  打包并转成dex

> **选中工程,常规流程导出即可(一定注意:打包请不要把接口文件打进来,我就是因为把接口文件打包进了,出现了这个异常!**
> **java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation**)
> **将打包好的jar拷贝到SDK安装目录android-sdk-windows\platform-tools下(注:这个目录没有的话,在build-tools目录会发现dex.bat批处理指令),DOS进入这个目录,执行命名:
dx --dex --output=testdex.jar test.jar
2.1.4  调用例子(反射调用-->本文我把jar优化后的testdex.jar从assets目录下复制到了SD卡下来反射加载的;  接口插件--->把testdex.jar从assets目录下复制到了data/data/包名/files目录下来处理的)
/*法一:把优化后的jar(testdex.jar)复制到SD卡下,通过反射来调用插件的方法*/
FileUtil.copyAssetJarToFile(this, "testdex.jar", "testdex.jar");
File file = new File(Environment.getExternalStorageDirectory().toString() + File.separator + "testdex.jar");
File optimizedDexOutputPath = getDir("temp", Context.MODE_PRIVATE);
/**
* DexClassLoader类加载器构造的四个参数
* String dexPath:the list of jar/apk files containing classes and resources, delimited by File.pathSeparator, which defaults to ":" on Android
*                  需要装在的apk或者jar文件的路径,包含多个路径用File.pathSeparator间隔开,在Android上默认是“:”
* String optimizedDirectory:directory where optimized dex files should be written; must not be null
*                  优化后的dex文件存放目录,不能为null
* String libraryPath:the list of directories containing native libraries, delimited by File.pathSeparator; may be null
*                  目标类中使用的c/c++库的列表,每个目录用File.pathSeparator间隔开,可以为null
* ClassLoader parent:  the parent class loader
*                  该类装载器的父装载器,一般用当前执行类的装载器
*/
DexClassLoader dexClassLoader = new DexClassLoader(file.getAbsolutePath(),
optimizedDexOutputPath.getAbsolutePath(),
null,
getClassLoader());

try {
Class<?> loadClass = dexClassLoader.loadClass("com.putaolab.dex.Iclass");
Constructor<?> constructor = loadClass.getConstructor(new Class[]{Context.class});
/*法一:反射调用方法*/
Method method = loadClass.getMethod("getData", null);
String data = (String) method.invoke(constructor.newInstance(this), null);
Log.e(tag, "data---"+data);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


2.2 方案二:(把接口作为联系主程序和插件程序的桥梁,要实现往程序通过接口调用插件的程序,那么主程序和插件程序必须有相同接口的文件,也就两个程序里都有接口的java类文件)

/*法二:把优化后的jar(testdex.jar)复制到data/data/包名/files/目录下,通过接口来*/
FileUtil.copyAssetJarToData(this, "testdex.jar", "testdex.jar");
File file = new File(this.getFilesDir().getAbsolutePath() + File.separator + "testdex.jar");
File optimizedDexOutputPath = getDir("temp", Context.MODE_PRIVATE);
DexClassLoader dexClassLoader = new DexClassLoader(file.getAbsolutePath(),
optimizedDexOutputPath.getAbsolutePath(),
null,
getClassLoader());

try {
Class<?> loadClass = dexClassLoader.loadClass("com.putaolab.dex.Iclass");
Constructor<?> constructor = loadClass.getConstructor(new Class[]{Context.class});
/*法二:*/
Iinterface newInstance = (Iinterface) constructor.newInstance(this);
String data = newInstance.getData();
Log.e(tag, "data---"+data);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


源代码下载地址:本文相关代码

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 类加载器