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(); }
源代码下载地址:本文相关代码
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories