一、思路
1、这段时间因为要做一个自定义的3Dwidget,这个widget是一个时钟,想实现的功能是可以给该widget更换皮肤(View)和交互,皮肤都是又图片和字符串组成的,但是又要考虑可能用户会选择不同的皮肤(皮肤中的某些元素不需要,又或者多添加一些元素),开始想吧,可以将所有的对象都先实例化,然后再在SD卡的配置文件中读取哪些是需要的元素,但是这样太有局限性了,一个是内存会耗费,另一个是根本就不灵活。偶然在Q群看到胡哥给的一个用.class文件创建对象的文章,那么我想可不可以在android里用动态加载的方式来切换皮肤呢?我的每个类所需要做的并不多,而且每个不同皮肤都是在另一个类(类似一个ViewGroup)中被调用,那个类几乎就不需要更改。那如果我将这些类的所必须的方法抽出来做一个接口,那么ViewGroup中只要调用这个接口的方法即可,具体的实现由其子类实现。
2、整理了一下思路,决定用上一个代理模式。
public interface ITest { public void log(String content); }
public class Test implements ITest { ITest test; public Test(Context context) { getTestInstanceDynamicFromSDCard(); } private void getTestInstanceDynamicFromSDCard() { // get test instance by dynamic } @Override public void log(String content) { test.log(content); } }
如此一来ViewGroup中只要实例化Test类,调用相应的方法即可,而其具体做什么将有其内部getTestInstanceDynamicFromSDCard所得到ITest对象实现。那么具体的问题就是如何动态加载一个类并创建其对象!
二、ClassLoader类来加载
1、看了胡哥推荐的用.class文件创建对象,于是也跟着用类似的方法来实现:
(http://wlh0706-163-com.iteye.com/blog/2098619)
2、但是总会失败,并且报错“can't load this type of class file”查了资料后才知道是虚拟机的问题!
在使用标准Java虚拟机时,我们经常自定义继承自ClassLoader的类加载器。然后通过defineClass方法来从一个二进制流中加载Class。(为什么要继承ClassLoader?如果不继承他就无法使用defineClass方法),但是在android的Dalvik虚拟机里走不通,但是android有提供两个类以供使用PathClassLoader、DexClassLoader
三、DexClassLoader加载(从SD卡加载)
1、PathClassLoader因为路径设计到system/app,故不作考虑。
2、DexClassLoader可以动态加载.apk、.jar和.dex文件而且路径不受限制,而且根据我的需求,显然是将自己分离的类打包成jar包会很灵活,因为这样我可以指定主程序对哪个路径的jar包进行加载(便于切换资源)
3、将所有程序都编译好后,包括需要动态加载的类也放在同一主程序运行以保证程序正常,将需要动态加载的隔离开,如实现一个DemoTest,放到com.example.out包下
package com.example.out; import android.util.Log; import com.example.biz.ITest; public class DemoTest implements ITest { @Override public void log(String content) { Log.d("example", content); } }
4、导出成jar包(eclipse直接右击该类export->java->jar file->next->存储目录+jar报名,不如就叫Dynamic.jar->finish),此时可以将原项目中的插件部分删除咯!
5、将Dynamic。jar拷贝到android-sdk-windows\platform-tools下将其转换成DexClassLoader所能识别的二进制jar包:cd 到platform-tools目录下,执行命令dx --dex --output=DynamicTest.jar Dynamic.jar 其中DynamicTest.jar为新的jar包,是我们所需要的二进制jar包,Dynamic.jar 为eclipse直接导出的jar包
6、将DynamicTest.jar拷贝到SD卡,例如:../sbclock/DynamicTest.jar
7、程序实现动态加载:
package com.example.dynamic; import android.app.Activity; import android.os.Bundle; import com.example.biz.ITest; import com.example.biz.Test; public class MainActivity extends Activity { private ITest mTest; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTest = new Test(this); } @Override protected void onDestroy() { mTest.log("it is just a test"); super.onDestroy(); } }
Test类动态加载:
package com.example.biz;
import java.io.File;
import java.lang.reflect.Constructor;
import dalvik.system.DexClassLoader;
import android.annotation.SuppressLint;
import android.content.Context;
public class Test implements ITest {
private ITest mTest;
private Context mContext;
private String mJarPath;
private String mClassName;
public Test(Context context) {
mContext = context;
getTestInstanceDynamicFromSDCard();
}
@SuppressLint("NewApi")
private void getTestInstanceDynamicFromSDCard() {
// get test instance by dynamic
mJarPath = android.os.Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/sbclock/DynamicTest.jar";// 前半部分为获得SD卡的目录
mClassName = "com.example.out.DemoTest";//和导出之前的包名和类名保持一致
File dexOutputDir = mContext.getDir("dex", 0);//
File file = new File(mJarPath);
DexClassLoader classLoader = new DexClassLoader(file.getAbsolutePath(),
dexOutputDir.getAbsolutePath(), null, mContext.getClassLoader());
try {
Class<?> clazz = classLoader.loadClass(mClassName);
Constructor<?> constructor = clazz.getConstructor(new Class[] {});//得到构造器
mTest = (ITest) constructor.newInstance();//实例化
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void log(String content) {
mTest.log(content);
}
}
8、结果,当退出该程序时确实有打印:
D/example (28710): it is just a test
9、更换其他的实现方式,还是只需要使用这个框架,在Test类中注册一个广播,外来程序可以发送广播通过Intent将其路径名和包名传过来即可创建新的子类!
10.1、在切换成其他子类时需要注意的是子类的名称不要相同,在实践中本来想使用统一的包名和类名,结果因为其对象在程序内存中已经有了,所以不会再次创建!
10.2、导出的jar包其实就是主程序中的一部分,所以不论其类中需要导入其他的类(而该jar包不含有)也没关系,因为动态加载之后这个对象就是主程序中的一部分。
10.3.导出的文件资源的加载可以从主程序中加载,也可以从SD卡中加载(最好是SD卡,这样就不同的jar包可以对应不同的资源了)
10.4、这应该算是一个粗略的插件框架了,如果想实现功能多的插件,那还是得将接口考虑周到!
相关推荐
在Android开发中,动态加载是实现插件化、热修复等高级功能的关键技术。DexClassLoader作为Android系统的一部分,主要用于加载非应用主程序路径下的.dex文件,使得在运行时能够加载新的类库或代码,从而实现动态加载...
在Android开发中,动态加载Class是一项重要的技术,它允许应用程序在运行时加载未知或更新的类,从而提高软件的灵活性和可扩展性。这在处理插件化、热修复或者模块化开发时尤为常见。本篇文章将深入探讨如何在...
总结一下,DexClassLoader在Android开发中扮演着动态加载额外类库的角色,特别是在处理Assets目录下的.dex和.jar文件时。通过正确配置和使用,我们可以灵活地扩展应用的功能,同时避免方法数过多的问题。在实践中,...
在Android开发中,动态加载JAR(Java Archive)文件是一种常见的技术,它允许应用程序在运行时加载和执行不在原始APK文件中的代码。这种技术有多种应用场景,例如更新功能、热修复、插件化框架等。下面将详细介绍...
一、Android插件化开发,常见有三种实现方式: (1)Android 动态加载dex文件 (2)Android动态加载APK文件(代理模式) (3)Hook技术动态加载APK文件中的Activity 二、Android 动态加载dex文件 1.反射方式加载(较...
在Android开发中,有时我们需要实现动态加载功能,例如在运行时添加或更新功能模块,而无需重新编译和发布整个应用程序。这就是动态加载jar文件的作用。动态加载不仅可以提高应用程序的灵活性,还可以降低更新成本,...
在Android平台上,动态加载插件apk是一种常见的技术,它允许应用程序在运行时加载和执行未在主应用包中编译的代码。这种技术的核心在于实现应用程序的模块化,提高更新效率,减少应用体积,以及增强安全性。下面我们...
1. 创建自定义ClassLoader:通常,我们需要继承DexClassLoader,并在构造函数中指定.dex文件的位置(如SD卡或应用私有目录)。 2. 加载.dex文件:在自定义的ClassLoader中,覆盖findClass()方法,当需要加载某个类...
在Android开发中,"动态加载dex"是一种技术,它允许应用程序在运行时加载新的或更新的Dalvik执行文件(.dex格式),而不必通过Google Play或其他应用商店进行完整应用的更新。这种技术对于大型应用或者需要频繁更新...
DexClassLoader可以从非标准位置(如外部存储)加载`.dex`文件,而PathClassLoader则主要用来加载应用主 Dex 文件。为了实现动态加载,我们需要创建自定义的ClassLoader,并重写其关键方法,如`findClass()`。 首先...
在Android系统中,动态加载机制是一种关键的技术,它允许应用程序在运行时加载或者卸载代码模块,极大地提高了软件的灵活性和可扩展性。这一技术在实现插件化开发中尤为重要,因为它能让应用在不更新主程序的情况下...
在Android应用开发中,动态加载jar或dex文件是一种常见的优化技术,它允许应用程序在运行时加载新的代码或库,而不必通过更新整个apk来实现功能的扩展或修复。这种技术通常用于热修复、插件化或者模块化开发,能够极...
在Android应用开发中,动态加载和插件式开发是一种高级技术,它允许应用程序在运行时加载新的功能或更新,而无需用户重新安装整个应用。这种技术对于实现自动升级和提高用户体验具有重要意义。以下是对这个"android ...
在Android开发领域,APK动态加载是一项关键技术,它允许应用程序在运行时动态地加载和执行代码,从而提高软件的灵活性和可维护性。本研究主要关注如何实现这一技术,以及其在实际应用中的优势和挑战。 动态加载的...
【Android 逆向】类加载器 ClassLoader ( 使用 DexClassLoader 动态加载字节码文件 | 准备 DEX 字节码文件 ) https://hanshuliang.blog.csdn.net/article/details/121776627 博客源码
在Android开发中,动态加载是实现插件化和热修复技术的关键部分,它允许应用程序在运行时加载新的功能或更新代码而无需重新安装整个应用。本文将深入探讨如何在已安装的APK中加载类和资源,这在提高用户体验和减少...
总结一下,动态加载和加解密Dex文件是Android应用开发中增强安全性、优化性能的重要手段。通过`DexClassLoader`可以实现在运行时加载额外的代码,而对Dex文件进行加密则可以提高应用的防护级别。理解这些技术并熟练...
在Android开发中,插件化技术是一种高级技巧,它允许应用程序在运行时动态加载和卸载其他APK文件,从而实现模块化的应用架构。这种技术能够极大地提高代码的复用性和灵活性,使得开发者可以更新单个功能模块而无需...
在Android开发中,"免安装动态加载APK"是一种高级技术,它允许应用程序在运行时动态地下载并加载新的功能模块,而无需用户手动安装额外的APK文件。这种技术通常被称为插件化或者模块化开发,对于更新、扩展应用功能...