运行代码的时候,出现了java.lang.NoSuchMethodError
错误:
D/AndroidRuntime(10278): Shutting down VM
E/AndroidRuntime(10278): FATAL EXCEPTION: main
E/AndroidRuntime(10278): Process: com.*****.SmartControl, PID: 10278
E/AndroidRuntime(10278): java.lang.NoSuchMethodError: No virtual method isInFastStandbyMode()Z in class Lcom/*****/android/system/KKConfigManager; or its super classes (declaration of 'com.*****.android.system.KKConfigManager' appears in /system/framework/com.*****.android.jar)
E/AndroidRuntime(10278): at com.*****.SmartControl.iflytek.SceneBroadcastReceiver.onReceive(SceneBroadcastReceiver.java:24)
E/AndroidRuntime(10278): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2609)
E/AndroidRuntime(10278): at android.app.ActivityThread.access$1700(ActivityThread.java:151)
E/AndroidRuntime(10278): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1380)
E/AndroidRuntime(10278): at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(10278): at android.os.Looper.loop(Looper.java:135)
E/AndroidRuntime(10278): at android.app.ActivityThread.main(ActivityThread.java:5254)
E/AndroidRuntime(10278): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(10278): at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime(10278): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
E/AndroidRuntime(10278): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
原因也很明显,就是运行的时候没找到这个方法呗。这个方法是写在中间件里头的,编译的时候依赖了最新的中间件,所以编译通过。但应用运行在还没有最新中间件的系统,就报了这个错误。
最开始想到的办法就是,既然没这个方法,那就不执行咯,想当然地try-catch一下,结果发现依然会崩。这可咋办?
研究一下这个NoSuchMethodError
吧,通过一层层的继承,发现其是继承于Error
,注释里是这么说的:
Error is the superclass of all classes that represent unrecoverable errors. When errors are thrown, they should not be caught by application code.
这话是什么意思呢?或者可以看一下Exception
的注释。Error
和Exception
都是继承于Throwable
的。
Exception is the superclass of all classes that represent recoverable exceptions. When exceptions are thrown, they may be caught by application code.
相比之下,这就很明显了,Exception
是可以被抓住的,Error
是抓不住的,也不应该抓,而是该想办法解决。
那怎么解决?想到了一个办法,先用反射来找这个方法,找不到的话,会有NoSuchMethodException
,而Exception
是可以抓住的嘛。
try {
Class c = KKConfigManager.class;
c.getMethod("isInFastStandbyMode");
// 原来的代码
} catch (Exception e) {
e.printStackTrace();
}
这样,如果找不到方法,就会throw exception而不会执行原来的代码,找到的话,就会继续执行原来的代码,完美!
当然,最好的办法还是保证运行环境有这个方法啦。
2019.2.12更新:
Error
也是可以抓住的,只是不应该被抓,当Error
难以被处理时,比如是第三方SDK抛出Error等,可以通过以下方法解决:
try {
// do something, which may throw an error
} catch (Throwable t) {
t.printStackTrace();
}