android反射 方法参数,Android 中反射的使用

本文介绍了在Android中如何使用反射机制来动态加载代码和调用方法,包括通过不同方式获取对象、反射其他APK中的类、调用构造函数、操作属性和方法。还展示了如何在插件化场景下实现回调,通过接口让被调用端回传结果给调用端。

前言

目前在做一个Android开发板上运行的App,在使用一个第三方的视频库的时候发现他的jar和so库是以apk形式作为一个插件安装在设备上的。看了下他的一些代码,知道了使用的是java 的反射机制实现的。研究了下,把现在项目里的opencv有关的大量so和java也打包成了一个插件用反射去调用。

这样做的好处显而易见,原本35M的apk安装包分离成了一个主程序和两个插件,主程序只有4M左右。插件一般是不需要更新的,那么我们更新是就只需要更新4M的主程序就可以了。大大节省了流量。

下面就说下是怎么玩的,还有一些学习过程中遇到的问题。

知识点

对象

获取对象的三种方式

方式一

try {

//直接写Bean.Class获取class对象,然后调用Class对象的newInstance()构造出一个Bean的对象

Class> mClass = Bean.class;

//上面一行代码执行完成时,会执行Bean对象的static初始化块

Object o = mClass.newInstance();

//也可以使用泛型

//Class mClass = Bean.class;

//Bean o = mClass.newInstance();

} catch (Exception e) {

}

方式二

try {

//使用对象的全路径名,此方法也会执行对象的static初始化块

Class> mClass = Class.forName("com.***.***.Bean");

Object o = mClass.newInstance();

//如果想获取Class是不执行static初始化块可以使用下面的方法

//Class> mClass = Class.forName("com.***.***.Bean",false,getClassLoader());

} catch (Exception e) {

}

方式三

try {

//获取当Class时并不会执行静态初始化块,在newInstance时才会执行

Class> mClass =getClassLoader().loadClass("com.***.****.Bean");

Object o = mClass.newInstance();

} catch (Exception e) {

}

反射其他Apk里的方法

try {

//在android中反射其他apk的类只能使用这个方法(其实就是方式三),其他方法都会抛出ClassNotFoundExcption

//构造要反射apk的Context

Context pgCtx = getApplication().createPackageContext("其他apk的包名", (Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY));

//使用Context获取ClassLoader,并获取Class对象

Class> mClass = pgCtx.getClassLoader().loadClass("com.***.***.类名");

//获取对象

Object o = mClass.newInstance();

} catch (Exception e) {

Log.e(TAG, "testD: ", e);

}

createPackageContext()方法里面的flag参数:

CONTEXT_INCLUDE_CODE :把要使用的代码加载到当前进程中(如果加载的代码,发送崩 溃,当前应用也会崩溃),如果代码不能安全的加载到当前进程,将会抛出java.lang.SecurityException 异常。如果不设置这个flag将不限制代码的加载,getClassLoader()将返回默认的加载器(也就是当前应用的类加载器,那么就不能加载其他apk的类了,所以这个flag是必设的)

CONTEXT_IGNORE_SECURITY:忽略一些安全限制

CONTEXT_IGNORE_SECURITY:受限制的

带参数的构造方法

try {

//和获取Class对象和无参数的使用方式一样

Class> mClass =getClassLoader().loadClass("com.***.****.Bean");

//参数是参数类型,这里传的是String和Integer

Constructor constructor = mClass.getConstructor(String.class,Integer.class);

//传入两个参数,反射出一个对象

Object o = constructor.newInstance("hello",1);

//如果不知道具体的构造方法可以使用以下方法

//Constructor>[] constructors = mClass.getConstructors();获取所有构造方法

//constructors[0].getGenericParameterTypes();获取构造方法的参数类型

// ...

} catch (Exception e) {

}

属性

try {

Class> mClass = Bean.class;

Object object = mClass.newInstance();

//对于公开的属性

Field fieldA = mClass.getField("a");

fieldA.set(object, 1);

//对于私有属性

Field fieldB = mClass.getDeclaredField("b");//获取属性

fieldB.setAccessible(true);//设置可访问性

fieldA.set(object, "hello");//设置值

//获取所有公开属性

Field[] publicFields = mClass.getFields();

//获取所有属性

Field[] allFields = mClass.getDeclaredFields();

} catch (Exception e) {

}

方法

try {

//和属性的用法差不多

Class> mClass = Class.forName("com.***.***.Bean", false, getClassLoader());

Object o = mClass.newInstance();

//公开方法,无参数,无返回值

Method testA = mClass.getMethod("testA");

testA.invoke(o);

//私有方法,无参数,无返回值

Method testB = mClass.getDeclaredMethod("testB");

testB.setAccessible(true);//设置可访问性

testB.invoke(o);

//私有方法,有参数,有boolean返回值,三个参数(String ,int ,Integer),

//在反射中int和Integer是不能混用的

Method testC = mClass.getDeclaredMethod("testB", String.class, int.class, Integer.class);

testC.setAccessible(true);

boolean result = (Boolean) testC.invoke(o, "hah", 1, 1);//调用

} catch (Exception e) {

}

回调

在android中的应用场景中,可能我们需要一个插件去完成一个任务,完成后返回结果,这时就需要回调了。其实也不能称之为回调。简单说就是传一个对象到其他apk,然后其他apk拿到这个对象后,反射这个对象的方法,并调用。当然,前提是两个apk都是你写的。

例子

调用端

下面是调用端的工具类:

public class ReflectTools {

private static final String TAG = "ReflectTest";

private static Method methodTestA = null;

private static Method methodTestB = null;

private static Object object = null;

public static void init(Application application) {

try {

//com.test.****是被调用apk的包名

Context pgCtx = application.createPackageContext("com.test.****", (Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY));

//com.test.****.ReflectInvoked被反射的类名

Class> mClass = pgCtx.getClassLoader().loadClass("com.test.****.ReflectInvoked");

//反射出来一个对象

object = mClass.newInstance();

//反射ReflectInvoked类中的方法,一个参数,类型是String

methodTestB = mClass.getMethod("testA", String.class);

//反射ReflectInvoked类中的方法,两个参数,类型是String和int(顺序不能乱)

methodTestA = mClass.getDeclaredMethod("testB", String.class, int.class);

} catch (Exception e) {

e.printStackTrace();

}

}

public static void testA(String msg) {

try {

//调用反射创建的object对象的testA()方法,传入参数msg,空返回值

methodTestB.invoke(object, msg);

} catch (Exception e) {

Log.e(TAG, "testA: ", e);

}

}

public static int testB(String msg,int code) {

try {

//调用反射创建的object对象的testB()方法,传入参数msg,code,int型返回值

return (int) methodTestA.invoke(object, msg);//调用

} catch (Exception e) {

Log.e(TAG, "send: ", e);

return -1;

}

}

/** * 设置一个回调 */

public static void setCallBack(CallBack callBack){

try {

methodCallBack.invoke(object, callBack);

} catch (Exception e) {

Log.e(TAG, "testA: ", e);

}

}

}

这是一个接口,用来让被调用端 回调 调用端。

其实就是两边约定某个类具有某个方法,那么一边有了这个类的对象之后就可以使用反射调用约定的方法

public interface CallBack {

//调用setCallBack()方法,传入一个CallBack的实现类,被调用端便可以回调onResult()方法。

void onResult(String result);

}

使用起来很简单,如下:

public class ReflectTestActivity extends Activity implements View.OnClickListener {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

ReflectTools.init(getApplication());

ReflectTools.setCallBack(new CallBack() {

@Override

public void onResult(String result) {

//由被调端 有处理结果时 回调

//do something

}

});

}

@Override

public void onClick(View v) {

if (v.getTag() == "testA") {

//调用testA()

ReflectTools.testA("hello");

} else {

//调用testB()

int a = ReflectTools.testB("hello",0);

}

}

}

被调用端

public class ReflectInvoked {

private static final String TAG = "ReflectInvoked";

private Object callBack;

/** * 设置一个回调 *@param o 回调对象 */

public void setCallBack(Object o) {

callBack = o;

}

/** * 调用本方法10s后回调调用者的methodForCallBack()方法 *@param msg 参数 */

public void testA(String msg) {

Log.d(TAG, "testA() called with: msg = [" + msg + "]");

new Thread(new Runnable() {

@Override

public void run() {

int i = 0;

while (i++ < 10)

SystemClock.sleep(1000);

callInvoker("hello invoker");

}

}).start();

}

public int testB(String msg, int flag) {

Log.d(TAG, "testB() called with: msg = [" + msg + "], flag = [" + flag + "]");

//do something

return 1;

}

/** * 回调本类发射的使用者,如果设置了CallBack; *@param result 事件处理结果 */

private void callInvoker(String result) {

if (null == callBack)

return;

try {

Method method = callBack.getClass().getMethod("onResult",String.class);

method.invoke(callBack,result);

} catch (Exception ignored) {

}

}

}

over…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值