基于类加载DexClassLoader的“插件”结构

这篇文章主要讲类加载器在android中如何动态的加载其他工程类的过程,对于类加载器的知识就跳过了。

1、首先需要创建两个工程,我创建的工程是classloader和classloaderplugin,前面的工程是主工程,后面是插件。现在classloader工程需要调用classloaderplugin插件中的类中的方法。在这里使用反射就能解决此问题。

1.1 首先看下classloaderplugin中类的方法,很简单返回两个数的和。

public class PluginClass implements Comm{

	@Override
	public int add(int a, int b) {
		 
		return a+b;
	}

}

1.2 创建类加载器和调用类里面的方法

       这个com.test.lb.plugin.classloaderplugin过滤器(IntentFilter)是配置在classloaderplugin项目中的,通过它就可以获取手机上匹配的插件项目,这里就能获取classloaderplugin,继而可以该项目的包名,路径等。

private DexClassLoader createWrapperClassLoader(){
		try {
			//intent 过滤插件
			Intent intent = new Intent("com.test.lb.plugin.classloaderplugin",null);
			PackageManager pm = getPackageManager();
			final List<ResolveInfo> plugins = pm.queryIntentActivities(intent, 0);
			ResolveInfo rInfo = plugins.get(0);
			ActivityInfo activityInfo = rInfo.activityInfo;
			
//			String div = System.getProperty("path.separator");
			packageName = activityInfo.packageName;
			String dexPath = activityInfo.applicationInfo.sourceDir;
			String dexOutputDir = getApplicationInfo().dataDir;
			String libPath = activityInfo.applicationInfo.nativeLibraryDir;
			
			return new DexClassLoader(dexPath, dexOutputDir, libPath, this.getClass().getClassLoader());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
     拿到类加载器cl之后,就可以加载类了,这里需要传入类的包名。通过newInstance创建一个对象,然后获取方法getMethod,第二个参数就是所调用方法的参数签名,最后通过invoke方法获取结果。运行时先要安装classloaderplugin即插件,然后在安装classloader主项目。
Class<?> clazz = cl.loadClass(packageName+".plugin.PluginClass");
			Object obj = clazz.newInstance();
			Class[] parameterTypes = new Class[2];
			parameterTypes[0] = Integer.TYPE;
			parameterTypes[1] = Integer.TYPE;
			Method method = clazz.getMethod("add", parameterTypes);
			
			tv_reflect_result.setText("反射调用: 20+30= "+method.invoke(obj, 20,30));

1.3 接口模型的“插件”

上面是通过反射调用方法来实现的,接着采用接口方法来实现。

首先创建一个接口,它位于classloader项目中,然后将改接口编译成一个jar包,在将这个jar包放到classloaderplugin中以library的形式添加到build path 中。接口定义如下:

public interface Comm {
	public int add(int a, int b);
}
创建类加载和1.2都是一样的,不同的事这次在newInstance时直接进行强制转换,Comm comm = (Comm) clazz.newInstance();直接转换成Comm接口,然后就直接调用里面的方法。

/**
	 * 通过反射创建出对象然后将其强制转换成接口类型
	 */
	private void useDexClassLoaderIntf(){
		try {
			Class<?> clazz = cl.loadClass(packageName+".plugin.PluginClass");
			Comm comm = (Comm) clazz.newInstance();
			tv_result.setText("接口调用: 20+30= "+comm.add(20,30));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
1.4 项目结构

                

1.5 基于上面的模式,写了一个简单的切换主题的效果

基本思路是,根据包名获取Resources对象,在通过类加载的创建一个对象并强制将其转换成颜色id的接口,在通过Resources的getColor方法获取颜色值。获取颜色的接口如下:第一个是背景色,第二个是文本的颜色,第三个是文本背景色。

public interface ColorIntf {
	public int getBackgroundColorId();
	
	public int getTextFontColorId();
	
	public int getTextBackgroundColorId();
}
在两个项目classloader和classloaderplugin中分别加入颜色值如:
  <color name="background">#cdcdf5</color>
    <color name="textbackground">#FF55bb</color>
    <color name="text">#ccffaf</color>

   <color name="background">#CDCDCD</color>
    <color name="textbackground">#FF5555</color>
    <color name="text">#000000</color>

在调用下面的方法给各个空间赋值,会根据传入不同的包名去加载不同的颜色实现类。

	private void useDexClassLoaderColorIntf(String packagename){
		try {
			Class<?> clazz = cl.loadClass(packagename+".plugin.ColorClass");
			ColorIntf colorIntf = (ColorIntf) clazz.newInstance();
			Resources resources = readResources(packagename);
			tv_result.setTextColor(resources.getColor(colorIntf.getTextFontColorId()));
			tv_result.setBackgroundColor(resources.getColor(colorIntf.getTextBackgroundColorId()));
			ll_main.setBackgroundColor(resources.getColor(colorIntf.getBackgroundColorId()));
			tv_reflect_result.setTextColor(resources.getColor(colorIntf.getTextFontColorId()));
			tv_reflect_result.setBackgroundColor(resources.getColor(colorIntf.getTextBackgroundColorId()));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

1.6 最后效果图

     

下载地址




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值