Android动态加载技术初探
一、前言:
现在,已经有实力强大的公司用这个技术开发应用了,比如淘宝,大众点评,百度地图等,之所以采用这个技术,实际上,就是方便更新功能,当然,前提是新旧功能的接口一致,不然会报Not Found等错。
二、原理:
2.1 JAR文件:
Android使用动态加载的方法,和Java加载类似,都是加载.jar文件来实现,只不过,不同的是,这两者的虚拟机不同,导致.jar的格式也不同。
Android只认识.dex格式的.class文件,因为,需要做的是:
1. 正常的方法Export出一个.jar文件;
2. 使用命令将.jar转成.dex格式的.jar文件;
命令: dx --dex --output=[path]/[dest].jar [path]/[src].jar
2.2 ClassLoader:
Android系统提供了两种ClassLoader:
1. DexClassLoader
这个可以加载jar/apk/dex,也可以从SD卡中加载,也是本文的重点。
2. PathClassLoader
只能加载已经安装到Android系统中的apk文件。
三、实战:
3.1 创建一个Jar的空工程(这里我取名叫:DynamicLoaderLib)
1. 新建两个.java文件,一个是IDynamicLoader.java(接口类),一个是LibDexJar.java(接口的实现类)
2. 代码
IDynamicLoader.java
package com.chris.dynamic.loader; public interface IDynamicLoader { public String getHelloWorld(); }
LibDexJar.java
package com.chris.dynamic.loader; public class LibDexJar implements IDynamicLoader { @Override public String getHelloWorld() { return "HelloWorld! (使用动态加载方法)"; } }
3. 导出jar包 (Export -> jar文件)
然后点"完成"就行了(千万不要将接口定义类也打包进去,否则在运行时会报错,只打包接口实现类就行)。
大家可以随意存放,不过,为了方便维护,我在当前这个工程下面建了一个jar目录来存放。
然后,打开命令行,输入命令:
dx --dex --output=[全路径]/dst.jar [全路径]/src.jar
注:大家需要把Android SDK的路径添加到系统的环境变量中,这样才能让系统找到dx工具,否则系统会报找不到。
这样,就生成好了我们所需要的dex格式.class的jar包,然后把这个放到手机的/mnt/sdcard目录下(因为这个目录是可读写的)。
3.2 创建一个Test工程(DynamicLoaderTest)
IDynamicLoader.java就是上一个JAR工程中的接口定义类,这里只给出MainActivity.java的实现:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button dloader = (Button) findViewById(R.id.dload_jar); dloader.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { File dexJar = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "LibDexJar.jar"); if(dexJar.exists()){ DexClassLoader dcl = new DexClassLoader(dexJar.getAbsolutePath(), Environment.getExternalStorageDirectory().toString(), null, getClassLoader()); try { Class dloaderClass = dcl.loadClass("com.chris.dynamic.loader.LibDexJar"); IDynamicLoader IDloader = (IDynamicLoader) dloaderClass.newInstance(); Toast.makeText(MainActivity.this, "Android动态加载Demo:" + IDloader.getHelloWorld(), Toast.LENGTH_SHORT).show(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } }); }
这里可以分为4步:
1. 判断是否存在LibDexJar.jar文件在sdcard目录下;
2. 使用DexClassLoader加载JAR文件;
3. 载入Class;
4. 获取接口类的实例;
然后,就可以使用接口类中开放的接口了。
附上我运行的截图:
最后,附上我的两个工程的源码供大家下载参考:
http://download.csdn.net/detail/qingye_love/6386981
大家多在本文章中来讨论,多多交流,谢谢!
另附上将导致的jar生成dex的jar(在代码的JAR目录下,这里我也贴出来):
dexjar.bat
@echo off rem 使用前请先设置自己的Android SDK路径 set ANDROID_SDK="E:\chris\Android_Dev\Android\android-sdk" set path=%path%;%ANDROID_SDK%\platform-tools; rem 设置jar所存放的路径 set JAR_ROOT="E:\chris\Android_Dev\eclipse\workspace\DynamicLoaderLib\jar" rem 编译 @echo on dx --dex --output=%JAR_ROOT%\LibDexJar.jar %JAR_ROOT%\dynamic.jar