【问题标题】:Play Store Crash Report: IllegalStateException on android.view.View$DeclaredOnClickListener.onClickPlay 商店崩溃报告:android.view.View$DeclaredOnClickListener.onClick 上的 IllegalStateException
【发布时间】:2017-10-19 19:24:59
【问题描述】:

我的一个应用收到了一些有关 IllegalStateException 的崩溃报告。 Stack Traces 说它来自 android.view.View$DeclaredOnClickListener.onClick(view)。我在测试或日常使用中从未遇到过这个错误(我自己每天在运行 Android 6.0.1 的三星 Note 4 上使用app)。老实说,我不知道从哪里开始看,因为堆栈跟踪似乎甚至没有引用我自己的任何代码,只是平台代码。我错过了什么?此版本确实使用了支持库,但不使用片段,这是该错误的其他解决方案所指的地方。

下面我粘贴了一个堆栈跟踪。这是来自运行 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)

【问题讨论】:

  • 会为您在布局 XML 中指定 onClick 属性的每个 View 创建一个 DeclaredOnClickListener。如果没有来自IllegalStateException 的消息,或更具体的堆栈跟踪,很难说到底是什么问题。可能是由于某种原因找不到声明的方法,该方法中的某些东西在被调用时引发了另一个异常,等等。不过,这将是开始寻找的地方。
  • 不知道我以前是怎么错过的,但底部的InvocationTargetException 表明您的onClick 方法之一中的某些东西正在引发另一个异常。也就是说,不是找不到或无法访问该方法,而是该方法内部的某些内容失败了。这就是你得到的所有堆栈跟踪吗?
  • 这就是我在 Play 商店开发者控制台上看到的全部内容。如果有什么地方可以找到更多,我不知道。
  • 嗨,斯科特,我面临着完全相同的问题,我无法在我的任何设备或模拟器中重现它。您是否找到问题的原因或解决方法?谢谢!

标签: java android google-play illegalstateexception


【解决方案1】:

抱歉,答案很长,但我认为解释如何深入 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”。反射采用此方法的字符串表示,并尝试调用该名称的指定类的方法。

当所需的方法不存在时会发生反射错误,例如名称错误、方法是私有的或参数不同。

请注意,在这种情况下,有两种不同的异常,一种是非公共方法,另一种是无法执行它。我不知道为什么您的堆栈跟踪没有与 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=”。然后在你的应用程序中搜索所有同名的方法并确保它们采用单个视图作为一个参数(确保你也在文件中导入“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?)。因此,您可能很难重现它,因为特定设备可能会以某种方式确定性地迭代它们,但不一定与其他设备/实现方式相同。

我希望这会有所帮助!请告诉我结果如何,我是一名研究生,正在研究诸如此类的软件缺陷,所以细节对我非常有用。

【讨论】:

  • 我喜欢长答案,谢谢!我将在我的 XML 中查找 onClicks。我没有想到这个问题可能存在而不是在 java.util 中。我不确定为什么我看不到错误消息 - Google 给我的只是错误本身,而不是任何其他日志记录。
  • 请注意,我不一定说问题出在 XML 中,可能是您需要在 xml 和 java 代码中完全重命名单击侦听器,以避免与其他方法发生冲突。
  • 非常感谢您的回答,但我可能无法解决这个问题。我所有的 onClick 调用都是针对公共方法的。它们都是唯一的名称,只有一种实现。而且我自己也无法复制这个问题。
  • 看起来这也可能来自在方法中抛出异常:stackoverflow.com/questions/6020719/…。因此,如果您的点击侦听器之一抛出空指针异常或可能导致它的其他东西?
【解决方案2】:

我最近收到了我的两个程序之一的相同类型的错误报告,这些崩溃发生在 Android 6.0.1 和 7.1 上。受影响的应用程序已经在商店中销售了好几个月,但这种现象对我来说是全新的,并且在几天内重复出现,从统计数据的角度来看是不太可能的。

然而,FearTheCron 的解释非常有帮助,但最终并不令人满意。首先,“非法状态异常”应该出现在第 4455 行,但是第 4455 行处理了“IllegalAccessException”,而第一个在第 4458 行处理。这是一个矛盾,我没有任何解释。也许这是 Java VM 中的一个错误。

此外,我检查了我的应用程序中的所有“android:onClick”条目和回调,所有这些都有相当独特的名称,因此没有具有相同名称和不同参数的变体。

这些检查让我认为问题不是由应用程序中的编码错误引起的,而是由 Android 的不当行为引起的。

但是这怎么可能发生,又如何避免呢?我的一个应用程序使用两个活动,而另一个只使用一个,但带有片段。只有具有两个活动的应用程序受到影响。我的理论是,Android 对视图和活动感到困惑,可能是由一些奇怪的暂停/停止/销毁/创建/开始/恢复活动状态更改模式触发的,并试图将视图与错误的活动相关联。例如,我的 UM Player 的视图显示专辑的曲目,系统检测到对曲目的点击,但该点击被发送到其他活动,该活动显示设备上的专辑,无法处理点击曲目打回来。结果将如崩溃报告中所述。

因此,我将更改我的应用程序,使两个活动都有针对每个“android::onClick”的回调,并将忽略发送到错误处理程序的调用。

也许这会有所帮助。任何黑暗中的进一步光明将不胜感激。

【讨论】:

    【解决方案3】:

    我在 Play 商店中遇到了同样的错误。肯定没有足够的信息来快速指出问题。 FearTheCron 的回答让我查看了我的 xml 中的 android:onClick 语句。我有 6 个语句,起初没有发现任何问题,然后我注意到我无意中为其中一个语句创建了一个 setOnClickListener。在使用一个月的时间里,我在四款不同的手机和平板电脑上的测试中没有发现任何问题。我删除了 setOnClickListener。我不确定这是否能解决问题,但我应该更加小心。

    【讨论】:

      猜你喜欢
      • 2020-06-02
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      • 2018-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多