Dalvik中自定义类加载

本文介绍了Dalvik虚拟机中自定义类加载的技术,包括如何处理超过65536方法引用的应用,以及如何设计框架以动态加载可执行扩展。通过示例应用程序展示了分包和运行时动态加载类的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

翻译自:http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html
Dalvik虚拟机为开发者提供了执行自定义类加载的设备。与从默认位置加载Dalvik的可执行文件(dex文件)不同,一个应用可以可以在可选择的地方加载类,比如内部存储或者通过网络。
这种技术并不适应每个应用。实际上,很多应用没有这个也能运行良好。但是自定义类加载时有适用场景的。这有以下几种场景:

  • 大的应用会超过65536的方法引用,这个数字是一个dex文件支持的最大方法数,为了避免这个限制,开发者可以把将应用中这部分分成多个二级dex文件,在运行时加载他们。
  • 框架可以被设计成运行时去动态的加载来作为可执行的扩展。

我们已经创建了一个简单的app来演示分包和运行时动态加载类(注意由于以上说明的原因,这个app无法用Eclipse的ADT插件来构建,对应的,用Ant来构建,在Readme.txt中有细节)

这个app有一个简单的Activity,包含了一个组件库来展示Toast,这个Activity和资源在默认的dex文件中,然而这个依赖库代码存储在apk中的二级dex中,这需要一个修改构建的进程,以下会展示的更详细。

在依赖库被调用之前,app需要首先明确的加载二级dex文件。让我们看看有关的运行部分。

代码结构

这个应用包含3个类。

  • com.example.dex.MainActivity:调用依赖库的UI组件
  • com.example.dex.LibraryInterface依赖库的接口定义
  • com.example.dex.lib.LibraryProvider 依赖库的执行

这个依赖库在二级dex文件中,其他的类在默认的dex文件中。以下的构建进程的部分说明如何完成这个过程。当然,打包的方式由开发者处理的脚本有关。

加载类和调用方法

二级dex文件包含LibraryProvider,以应用assert的形式存储。首先,它必须要拷贝到加载类的加载器路径中。这个应用使用私有的内部存储区域来达到目的(从技术上来看,外部存储也能工作,不过需要考虑在那里保存二进制文件的安全隐患)

下面是MainActivity的截图,包含标准的文件I/O流来实现拷贝。

  // Before the secondary dex file can be processed by the DexClassLoader,
  // it has to be first copied from asset resource to a storage location.
  File dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE),
          SECONDARY_DEX_NAME);
  ...
  BufferedInputStream bis = null;
  OutputStream dexWriter = null;

  static final int BUF_SIZE = 8 * 1024;
  try {
      bis = new BufferedInputStream(getAssets().open(SECONDARY_DEX_NAME));
      dexWriter = new BufferedOutputStream(
          new FileOutputStream(dexInternalStoragePath));
      byte[] buf = new byte[BUF_SIZE];
      int len;
      while((len = bis.read(buf, 0, BUF_SIZE)) > 0) {
          dexWriter.write(buf, 0, len);
      }
      dexWriter.close();
      bis.close();

  } catch (. . .) {...}

下一步,声明一个dex加载器来从提取的二级dex文件中加载依赖库。有很多的方法来调用加载的类中的方法。在这个例子中,类被直接调用时,类实例转为一个接口。

另一个方法去调用方式是使用反射API。使用反射的方法的好处是不需要二级dex文件执行任何特定的接口。然而,应该知道反射是很慢的。

// Internal storage where the DexClassLoader writes the optimized dex file to
  final File optimizedDexOutputPath = getDir("outdex", Context.MODE_PRIVATE);

  DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
                                         optimizedDexOutputPath.getAbsolutePath(),
                                         null,
                                         getClassLoader());
  Class libProviderClazz = null;
  try {
      // Load the library.
      libProviderClazz =
          cl.loadClass("com.example.dex.lib.LibraryProvider");
      // Cast the return object to the library interface so that the
      // caller can directly invoke methods in the interface.
      // Alternatively, the caller can invoke methods through reflection,
      // which is more verbose. 
      LibraryInterface lib = (LibraryInterface) libProviderClazz.newInstance();
      lib.showAwesomeToast(this, "hello");
  } catch (Exception e) { ... }

创建进程

为了得到两个分开的dex文件,我们需要调整标准构建过程。为了实现这个,我们在ant的build.xml简单的修改-dex指令
这个修改过的-dex指令执行以下的操作:

  1. 创建两个临时文件夹类存储.class文件,来转换为默认dex文件和二级dex文件。
  2. 有选择地从PROJECT_ROOT/bin/classes 复制.class文件到两个临时文件夹
      <!-- Primary dex to include everything but the concrete library
                 implementation. -->
            <copy todir="${out.classes.absolute.dir}.1" >
                <fileset dir="${out.classes.absolute.dir}" >
                        <exclude name="com/example/dex/lib/**" />
                </fileset>
            </copy>
            <!-- Secondary dex to include the concrete library implementation. -->
            <copy todir="${out.classes.absolute.dir}.2" >
                <fileset dir="${out.classes.absolute.dir}" >
                        <include name="com/example/dex/lib/**" />
                </fileset>
            </copy>
  1. 从两个临时文件夹转换.class文件成两个分开的dex文件
  2. 添加一个二级dex文件到jar文件中,jar文件为DexClassLoader提供输入格式。最后,将jar文件存储在项目的assets文件夹中。
<!-- Package the output in the assets directory of the apk. -->
            <jar destfile="${asset.absolute.dir}/secondary_dex.jar"
                   basedir="${out.absolute.dir}/secondary_dex_dir"
                   includes="classes.dex" />

为了构建,在项目根目录下执行ant debug (或者release)。
这就是合适的场景,动态加载类会很有帮助。

内容概要:本文档详细介绍了基于MATLAB实现多目标差分进化(MODE)算法进行无人机三维路径规划的项目实例。项目旨在提升无人机在复杂三维环境中路径规划的精度、实时性、多目标协调处理能力、障碍物避让能力和路径平滑性。通过引入多目标差分进化算法,项目解决了传统路径规划算法在动态环境和多目标优化中的不足,实现了路径长度、飞行安全距离、能耗等多个目标的协调优化。文档涵盖了环境建模、路径编码、多目标优化策略、障碍物检测与避让、路径平滑处理等关键技术模块,并提供了部分MATLAB代码示例。 适合人群:具备一定编程基础,对无人机路径规划和多目标优化算法感兴趣的科研人员、工程师和研究生。 使用场景及目标:①适用于无人机在军事侦察、环境监测、灾害救援、物流运输、城市管理等领域的三维路径规划;②通过多目标差分进化算法,优化路径长度、飞行安全距离、能耗等多目标,提升无人机任务执行效率和安全性;③解决动态环境变化、实时路径调整和复杂障碍物避让等问题。 其他说明:项目采用模块化设计,便于集成不同的优化目标和动态环境因素,支持后续算法升级与功能扩展。通过系统实现和仿真实验验证,项目不仅提升了理论研究的实用价值,还为无人机智能自主飞行提供了技术基础。文档提供了详细的代码示例,有助于读者深入理解和实践该项目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值