-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android系统版本兼容ReflectiveOperationException问题 #5
Comments
看代码发现 ClassNotFoundExceptione 是 ReflectiveOperationException 的子类,于是修改如下 @TargetApi(Build.VERSION_CODES.KITKAT)
private static String getWakeLockTag(PowerManager.WakeLock wakeLock) {
String tag = "Default-WakeLock-Tag";
if (wakeLock == null) {
return tag;
}
try {
Method getTagMethod = wakeLock.getClass().getDeclaredMethod("getTag");
getTagMethod.setAccessible(true);
tag = (String) getTagMethod.invoke(wakeLock, (Object[]) null);
} catch (ReflectiveOperationException e) {
LogUtil.w(TAG,e);
} catch (Exception e) {
LogUtil.w(TAG,e);
}
return tag;
} 查看手机系统为Android4.2.2.r1源码: 有wakeLock 这个内部类,但是没有getTag这个方法。 且来看看高版本的方法: /** @hide */
public void setTag(String tag) {
mTag = tag;
}
/** @hide */
public String getTag() {
return mTag;
} 可以看出加了 @hide 对外不公开,但是系统内部可见的,所以这里要用反射。 |
以为万事大吉,谁知道报了java.lang.VerifyError: com/xxx/xxx/xxx/xxx/manager/WakeLockManager getWakeLockTag 是上述类WakeLockManager中的一个方法 查资料说是JVM加载类的时候,“校验器”检查文件格式虽然正确,但是内部的存在不一致性和安全性的问题,所以抛出了该错误。 不同的虚拟编译器不一样,所以抛出的错误信息叶铿不一样。 异常名称 异常栈中的段落信息 可能原因
Android 虚拟机注意 导致这个错误的原因有2个 三方jar包本身有错误 作者:泛原罪 |
看完上述的文章,还是没搞明白为什么会有这个错误接着看到另外一篇文章 文中说明出现这个异常的问题主要在类文件校验错误,出现这种情况的情况有:
但是,这个地方既然已经用了反射的,为什么还会报这个错误? |
查看了Android的API文档马上就发现,这个ReflectiveOperationException在19之后才加入,所以我们添加了注解: @TargetApi(Build.VERSION_CODES.KITKAT) 那么,加了该注解,我们应该对低版本进行下兼容处理。 @TargetApi(Build.VERSION_CODES.KITKAT)
private static String getWakeLockTag(PowerManager.WakeLock wakeLock,String wakeLockName) {
String tag = "Default-WakeLock-Tag";
if (wakeLock == null) {
return tag;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Method getTagMethod = wakeLock.getClass().getDeclaredMethod("getTag");
getTagMethod.setAccessible(true);
tag = (String) getTagMethod.invoke(wakeLock, (Object[]) null);
} catch (ReflectiveOperationException e) {
LogUtil.w(TAG,e);
} catch (Exception e) {
LogUtil.w(TAG,e);
}
}else {
LogUtil.d(TAG, "api < 19 ,so wakeLockName: " + wakeLockName);
return wakeLockName;
}
return tag;
} |
经过验证,还是报了如下相同异常AndroidRuntime: FATAL EXCEPTION: Thread-21891
java.lang.VerifyError: com/xxx/xxx/xxx/xxx/xxx/WakeLockManager
at com.xxx.xxx.xxx.xxx.b.b.b(Unknown Source)
at com.xxx.xxx.xxx.xxx.b.b.a(Unknown Source)
at com.xxx.xxx.xxx.xxx.b.b$1.run(Unknown Source) 如果在5.0.0的机器上跑,则不存在该问题。 |
查看这个class的文件,发现如下:Constant pool:
#63 = Class #191 // java/lang/ReflectiveOperationException
#117 = Utf8 Ljava/lang/ReflectiveOperationException;
#119 = Class #191 // java/lang/ReflectiveOperationException
#191 = Utf8 java/lang/ReflectiveOperationException |
查JVM虚拟机类加载机制中验证步骤,发现:
ReflectiveOperationException这个就是在低版本Android系统中不被支持的,所以在低版本Android系统中加载该WakeLockManager类时就报:java.lang.VerifyError。 |
上述的说法并不完全正确,因为发现如果我们修改代码如下: private static String getWakeLockTag(PowerManager.WakeLock wakeLock,String wakeLockName) {
String tag = "Default-WakeLock-Tag";
if (wakeLock == null) {
return tag;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Method getTagMethod = wakeLock.getClass().getDeclaredMethod("getTag");
getTagMethod.setAccessible(true);
new ReflectiveOperationException("test");// 直接New一个,而不是在catch的代码块里面
tag = (String) getTagMethod.invoke(wakeLock, (Object[]) null);
}catch (Exception e) {
LogUtil.w(TAG,e);
}
}else {
LogUtil.d(TAG, "api < 19 ,so wakeLockName: " + wakeLockName);
return wakeLockName;
}
return tag;
} 这样在运行时,并不会报错。 |
那么catch里面和直接在代码里面直接去new有什么区别呢?
所以,出现了上述的现象。在代码中 |
反射获取getTag接口报ReflectiveOperationException
The text was updated successfully, but these errors were encountered: