Android版本限制反射,低版本Android反射引起的一个奇怪的Bug

本文讲述编写测试代码时,在XML布局指定View的点击事件,在4.0运行正常,低版本(低于2.3)出错。原因是系统处理XML中onClick事件用反射,不同版本Dalvik虚拟机对反射处理不同,低版本提前初始化函数返回值和参数易出错。开发者兼容低版本时要注意反射使用。

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

在上个月编写一个测试代码的时候,遇到一个奇怪的问题。

在XML布局中指定一个View的 android:onClick=”test” 事件函数。在4.0中运行程序没问题,而在低版本(低于2.3)手机中运行会出错,错误内容为 NoSuchMethodException(找不到这个test函数)。 当时也没详细研究具体原因是啥,只是在Java代码中通过View的setOnClickListener函数来设置点击事件接口在低版本运行就没问题了。

今天看到Square  的一篇博文才明白为啥会出现这个诡异的Bug。

下面来详细介绍下这个情况。

如果您在Activity中覆写了高版本的API,比如 在 API 16(Jelly Bean)中引入的API

Java

@Override

public void onPrepareNavigateUpTaskStack(TaskStackBuilder builder) {

super.onPrepareNavigateUpTaskStack(builder);

}

1

2

3

4

@Override

publicvoidonPrepareNavigateUpTaskStack(TaskStackBuilderbuilder){

super.onPrepareNavigateUpTaskStack(builder);

}

如果程序运行在低版本的系统中,由于不会调用该函数, 所以应该是没有问题的。

如果您在该Activity的Layout xml文件中,设置了View 的 android:onClick=”test” 属性,则这个时候运行在低于2.3版本的手机上就会异常 — 就是上面提到的,该点击事件函数找不到。

导致该异常的原因

由于系统处理XML 中 onClick 事件函数的方式为反射,就如同您通过代码

TestActivity.class.getMethod(“test”, View.class) 来查找这个点击事件处理函数,在不同版本的Dalvik虚拟机中对反射的处理方式是不一样的:

在ICS中,Dalvik虚拟机调用一些C代码来查询.dex文件,看看有没有 test 函数,如果有的话就返回一个 Method对象。

而在 Froyo(2.2)中,Dalvik虚拟机调用一些C代码来查询.dex文件,然后查找TestActivity中的所有函数,把该函数集合返回到Java代码中。然后Java代码在这个集合中搜索test函数。

查询一个函数并不代表要执行该函数,类初始化比较耗时应该在使用的时候才去初始化。 而在 Froyo中,Dalvik虚拟机提前初始化 每个函数的返回值和参数。如果这些返回值和参数对象任何一个初始化失败了,就出现问题了。

前面我们在处理点击事件的时候,需要通过反射查询这个test函数,而Dalvik加载了TestActivity的所有函数。当然还包含onPrepareNavigateUpTaskStack这个4.1系统中引入的函数,而该函数的参数TaskStackBuilder 在2.2版本中并不存在。当Dalvik虚拟机初始化该函数的时候遇到了问题,从而导致查找处理点击事件的test函数失败。

这种问题导致开发者很难知道为何会出现这个 NoSuchMethodException, 明明在TestActivity中声明了这个参数为View的test函数。

所以在兼容低版本(小于2.3)设备的时候,开发者一定要注意对反射的使用。可以通过Lint来检测是否在代码中使用了低于android:minSdkVersion所指定的版本中的API。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值