java - Play 商店崩溃报告 : IllegalStateException on android. view.View$DeclaredOnClickListener.onClick

标签 java android google-play illegalstateexception

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

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

最佳答案

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

当需要的方法不存在时会发生反射错误,比如名字写错了,方法是private的,或者参数不一样。

请注意,在这种情况下有两种不同的异常,一种是非公共(public)方法,另一种是无法执行它。我不知道为什么您的堆栈跟踪没有与 IllegalStateException 关联的消息,但制造商可以根据需要修改此代码。

我怀疑你有一个正确名称的方法,因为如果名称错误,解析方法函数会抛出不同的错误:

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    }

所以这给我们留下了两种我能想到的可能性:它找到的方法有错误的签名或者它找到的方法是静态/私有(private)的。

我将如何进行调试:

我猜你在你的 xml 某处指定了一个点击监听器(在你的 xml 文件中寻找“android:onClick=”。然后在你的应用程序中搜索同名的所有方法,并确保它们采用单个 View 作为一个参数(确保你也在文件中导入“android.view.View”,因为导入错误的 View 可能会导致这种情况)。还要确保它们不是静态的。它也可能值得寻找私有(private)的东西,因为这可以也会导致问题,但根据您的堆栈跟踪,它似乎不太可能。

为什么这个问题可能难以重现:

如果您注意到 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?)。因此,您可能很难重现它,因为特定设备可能会以某种方式确定性地迭代它们,但不一定与其他设备/实现方式相同。

希望对您有所帮助!请告诉我结果如何,我是一名研究生,正在研究诸如此类的软件缺陷,因此详细信息对我来说非常有用。

关于java - Play 商店崩溃报告 : IllegalStateException on android. view.View$DeclaredOnClickListener.onClick,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44073861/

相关文章:

android - 为微调项设置 onClickListener?

android - Glide Picasso 不会加载本地存储视频的缩略图路径

oauth-2.0 - 使用在Google API控制台中生成的 token 与Google Play API进行通信

java - 从 GAE 上传和下载 blob

java - 如何使用需要正确 HTML 的库处理来自 Web 的无效 HTML 文档

java - Android 将位图写入 SD 卡

java - 无法启动 Intent

android - 如何在android中测试应用内购买?

android - 启用 Google App Signing 后出现 "The AndroidManifest.xml of the uploaded APK could not be parsed. Was it compiled properly?"错误

java - 在 postman 帖子请求中发送 map