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

posted on 2013-10-12 23:10  新一  阅读(405)  评论(0编辑  收藏  举报

导航