安卓实现动态加载class

来源:互联网 发布:七彩网络下载 编辑:程序博客网 时间:2024/06/01 12:04

前两天与老师讨论到命令模式的使用,提到了类的动态加载,即从外部加载进class。动态加载在之前有看到过,但没有留意,于是今天特意写了个demo测试一下。首先介绍一下类加载器的概念,内容由百度而来。

类加载器的基本概念

  类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java )在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class )。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

类加载器的树状组织结构

  Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:

  引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader。

  扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

  系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader() 来获取它。

  除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader 类的方式实现自己的类加载器,以满足一些特殊的需求。

需要注意的是,安卓中开发人员可用的类加载只有DexClassLoader和PathClassLoader。并且后者只能加载已经安装了的apk中的class。今天我用到的是DexClassLoader,实现从SD卡中加载class。demo中还用到了反射,对反射不熟悉的朋友可以百度“java 反射”。

首先新建一个安卓工程,按照平时的步骤就可以了,package我设置为com.everlin.loadtest。然后在工程中新建一个包路径:com.everlin.loadtest.jar,在这个包中新建一个JarTest类:

package com.everlin.loadtest.jar;import android.content.Context;import android.widget.Toast;public class JarTest {public static void show(Context context){Toast.makeText(context, "加载成功!", Toast.LENGTH_LONG).show();}}
接着将该包导出为jar包:在项目浏览器主公点击选择包》File》Export》java》jar file》next》填写导出路径》finish。我导出的文件为test.jar

导出后要将jar包转换为dex:把刚才导出的jar文件复制到你安卓sdk安装路径下的"build-tools\版本\"文件夹下,我电脑的路径是“D:\Program Files\eclipse\android_sdk\build-tools\18.1.0”。

然后在该路径打开命令行窗口,输入“dx --dex --output=保存路径 源路径”。如我的是:“dx --dex --output=my.jar test.jar”。完成后会在这个路径下生成my.jar文件,这个就是处理后的dex。把他复制到模拟器的文件系统中,我放在了“sdcard\everlin\my.jar”。

接下来重新进入eclipse,把刚才那个包删了,目的是为了效果明显,避免读者认为我们待会载入的是apk中的包。然后修改刚才自动生成的MainActivity类:

</pre><p><pre name="code" class="java">package com.everlin.loadtest;import java.io.File;import java.lang.reflect.Method;import dalvik.system.DexClassLoader;import android.os.Bundle;import android.os.Environment;import android.app.Activity;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//文件系统根目录String rootPath = Environment.getExternalStorageDirectory().toString();//我放置dex文件的路径String dexPath = rootPath + File.separator + "everlin" + File.separator+ "my.jar";//实例一个DexClassLoader,参数1为文件路径,参数2为处理路径。//我试了用文件系统卡的路径,但报错说路径不属于当前用户。查了资料说是因为内置存储的原因。//于是改成apk的安装路径,就正常了。DexClassLoader cl = new DexClassLoader(dexPath, getDir("dex", 0).getAbsolutePath(), null, getClassLoader());try {//加载类Class<?> test = cl.loadClass("com.everlin.loadtest.jar.JarTest");//利用反射,获取这个类的方法Method[] methods = test.getDeclaredMethods();//执行第一个方法,即JarTest.show()methods[0].invoke(null,getApplication());} catch (Exception e) {e.printStackTrace();}}}


调试工程,模拟器运行结果如下:



0 0
原创粉丝点击