我的一个应用程序为IllegalStateException选择了一些崩溃报告。 Stack Traces说它来自android.view.View $ DeclaredOnClickListener.onClick(查看)。我在测试或日常使用中从未遇到过这个错误(我每天都在运行Android 6.0.1的Samsung Note 4上使用app)。老实说,我不知道从哪里开始看,因为Stack Trace似乎甚至没有引用我自己的代码,只是平台代码。我错过了什么?此版本确实使用了支持库,但没有使用片段,这是此错误的其他解决方案所指的位置。
下面我粘贴了一个Stack Traces。这是来自运行Android 6.0的Moto G Turbo
java.lang.IllegalStateException:
at android.view.View$DeclaredOnClickListener.onClick(View.java:4455)
at android.view.View.performClick(View.java:5201)
at android.view.View$PerformClick.run(View.java:21163)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method:0)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Caused by: java.lang.reflect.InvocationTargetException:
at java.lang.reflect.Method.invoke(Native Method:0)
at android.view.View$DeclaredOnClickListener.onClick(View.java:4450)
答案 0 :(得分:4)
很抱歉答案很长,但我认为解释如何深入研究Android框架以调试问题很有用。
可以在此处访问抛出此异常的代码:
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/view/View.java
4452 try {
4453 mMethod.invoke(mHostView.getContext(), v);
4454 } catch (IllegalAccessException e) {
4455 throw new IllegalStateException(
4456 "Could not execute non-public method for android:onClick", e);
4457 } catch (InvocationTargetException e) {
4458 throw new IllegalStateException(
4459 "Could not execute method for android:onClick", e);
4460 }
反映及其在点击侦听器中的使用
基本上它正在做的是使用反射调用基于字符串的方法。此方法是由应用程序开发人员定义的方法,用于响应被单击的按钮。这通常是因为你可以通过XML指定onClickListener方法,例如你可以说调用“goDoWhatever”而不是通常的“onClick”。 Reflection采用此方法的字符串表示形式,并尝试在该名称的指定类上调用方法。
当所需方法不存在时会发生反射错误,例如,如果您输入的名称错误,方法是私有的,或者参数不同。
请注意,在这种情况下,有两个不同的异常,一个用于非公共方法,另一个用于不能执行它。我不知道为什么您的堆栈跟踪没有与IllegalStateException相关联的消息,但制造商可以根据需要修改此代码。
我怀疑你有一个正确名称的方法,因为如果名称错误,resolve方法函数会抛出不同的错误:
4463 @NonNull
4464 private Method resolveMethod(@Nullable Context context, @NonNull String name) {
4465 while (context != null) {
4466 try {
4467 if (!context.isRestricted()) {
4468 return context.getClass().getMethod(mMethodName, View.class);
4469 }
...
4485 throw new IllegalStateException("Could not find method " + mMethodName
4486 + "(View) in a parent or ancestor Context for android:onClick "
4487 + "attribute defined on view " + mHostView.getClass() + idText);
4488 }
4489 }
所以这给我们留下了两种我能想到的可能性:它找到的方法有错误的签名,或者它找到的方法是静态/私有。
我将如何进行调试:
我猜你在你的xml中指定一个点击监听器(在xml文件中查找“android:onClick =”。然后在你的应用程序中搜索所有相同名称的方法,并确保他们将一个View视为一个参数(确保你在文件中导入“android.view.View”也是因为导入错误的视图会导致这个)。还要确保它们不是静态的。也可能值得寻找私有的东西,因为这可以也会导致问题,但根据您的堆栈跟踪似乎不太可能。
为什么这个问题可能难以重现:
如果你注意到android框架中的方法“resolveMethod”只是返回同名的第一个方法,那么有一个类是有效的java:
class Foo{
void bar(String s){}
void bar(View s){}
方法签名由名称(例如“bar”)和参数列表组成(在这种情况下是包含一个项目“View”的列表或包含一个项目“String”的列表)。
此Android框架代码可能会找到“void bar(String s)”而不是“void bar(View s)”。这可能导致难以重现错误,因为反射找到方法的顺序是非确定性的(Java reflection: Is the order of class fields and methods standardized?)。因此,您可能很难再现它,因为特定设备可能以某种方式确定性地迭代它们,但不一定与其他设备/实现方式相同。
我希望这有帮助!请让我知道结果如何,我是一名研究软件缺陷的研究生,这样的细节对我来说非常有用。
答案 1 :(得分:0)
我最近收到了我的两个程序之一的同类错误报告,这些崩溃发生在Android 6.0.1和7.1上。受影响的应用程序已在商店中存放了好几个月,但这种现象对我来说是全新的,并且在几天之内重复,从统计角度来看是非常不可能的。
然而,FrearTheCron的解释非常有帮助,但最终并不令人满意。首先,"非法国家例外"应该出现在第4455行,但是第4455行处理了一个" IllegalAccessException",而第一行是在第4458行处理的。这是一个矛盾,我没有任何解释。也许它是Java VM中的一个错误。
此外,我检查了所有" android:onClick"我的应用程序中的条目和回调,并且所有这些都具有相当独特的名称,因此没有具有相同名称和不同参数的变体。
这些考试让我觉得问题不是由应用程序中的编码错误引起的,而是由Android不当行为引起的。
但这怎么可能发生,怎么可以避免呢?我的一个应用程序使用两个活动,而另一个只使用一个,但有片段。只有具有两个活动的应用程序受到影响。我的理论是Android与视图和活动混淆,可能由一些奇怪的暂停/停止/破坏/创建/启动/恢复活动状态更改模式触发,并尝试将视图与错误的活动相关联。例如,我的UM播放器的视图显示了专辑的曲目,系统检测到曲目上的点击,但此点击被发送到另一个活动,该活动显示设备上的专辑,无法处理点击曲目打回来。结果将如崩溃报告中所述。
因此,我将以这种方式更改我的应用程序,即两个活动都有每个" android :: onClick"的回调。并将忽略发送到错误处理程序的调用。
也许这有帮助。在黑暗中任何进一步的光都将受到高度赞赏。
答案 2 :(得分:0)
我在Play商店遇到了同样的错误。肯定没有足够的信息来快速指出问题。 FearTheCron的回答让我看看我的xml for android:onClick语句。我有6个语句,一开始没有看到任何问题,然后我注意到我无意中为其中一个创建了一个setOnClickListener。在一个月的使用中,我在四种不同的手机和平板电脑上的测试中没有发现任何问题。我删除了setOnClickListener。我不确定这会解决问题,但我应该更加小心。