Crash reporting to Store Store: IllegalStateException on android.view.View $ DeclaredOnClickListener.onClick

One of my applications has collected several crash reports for IllegalStateException. The stack traces say this comes from android.view.View $ DeclaredOnClickListener.onClick (view). I have never encountered this error in testing or daily use (I use the app myself on a daily basis on a Samsung Note 4 running Android 6.0.1). Honestly, I don't know where to start looking, because Stack Trace doesn't seem to even reference my own code, but platform code. What am I missing? This version uses the support library, but not the snippets referenced by other solutions to this error.

Below I have inserted one of the stacks. This is from Moto G Turbo running Android 6.0

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)

      

+3


source to share


3 answers


Sorry for the long answer, but I think it is helpful for explaining how to delve into the Android platform to debug the problem.

Access to the code that throws this exception:

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            }

      

Reflection and its use in click listeners

Basically what it does is call a string based method using reflection. This method is the one defined by the application developer for responding to a button click. This is usually done because you can specify the onClickListener method via XML, for example, you can say that "goDoWhatever" is called instead of "normal client". Reflection takes a string representation of this method and tries to call the method on the specified class of that name.

A reflection error occurs when the desired method does not exist, for example, if you misspelled the name, the method is private, or the parameters are different.

Note that there are two different exceptions in this case: one for a non-public method, and then another for failing to execute. I don't know why your stack trace has no IllegalStateException related message, but vendors can change this code if they want.

I suspect you have a method with the correct name, since the resolver method function throws another error if the name is incorrect:

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    }

      



So, this leaves us with two possibilities that I can think of: the method it finds has the wrong signature, or the method it finds is static / private.

How I would like to debug this:

I am assuming that you specify a click listener in your xml node (look at "android: onClick =" in your xml files. Then search the app for all methods with the same name and make sure they take the same kind as a parameter (make sure you import "android.view.View" into the file, as importing a wrong view can cause this.) Also make sure they are not static. Also it is probably worth looking for things that are private as this can also cause problems, but seems less likely based on your stack trace.

Why this problem can be difficult to reproduce:

If you notice that the "resolveMethod" method in the android framework just returns the first method with the same name, so if it is java for the class:

class Foo{
    void bar(String s){}
    void bar(View s){}

      

The method signature consists of a name (for example, "bar") and a list of parameters (in this case, a list with one "View" item or a list with one "String" item).

This Android platform code may find "void bar (String s)" instead of "void bar (View s)". This can make it difficult to reproduce the error, since the order in which the detectors discover is not deterministic ( Java reflection: Is the order of the fields and methods of a class ordered? ). As such, you might find it difficult to reproduce it, since a certain device seems to be deterministically iterating through them in some way, but not necessarily in the same way as another device / implementation.

Hope this helps! Please let me know how it turns out, I'm a graduate student doing research on software defects like this one so the details are very helpful to me.

+4


source


I recently received the same error reports for one of my two programs and these crashes happened on Android 6.0.1 and 7.1. The affected app was in the store for many months, but the phenomenon was completely new to me and repeated over the course of several days, which is statistically absolutely incredible.

However, FrearTheCron's explanations were extremely helpful, but finally not satisfying. First, the "illegal state exception" should appear on line 4455, but line 4455 handles the "IllegalAccessException" and the first one on line 4458. This is a contradiction that I don't have to explain. Perhaps this is a bug in the Java VM.

Also, I have checked all the "android: onClick" entries and callbacks in my application, and they all have fairly unique names and therefore do not have variants with the same names and different parameters.

These exams make me think that the problem is not caused by a coding error in the app, but by incorrect Android behavior.



But how could this have happened, and how can it be avoided? One of my apps uses two activities, while the other uses only one but with fragments. This only applies to an app with two actions. My theory is that Android is confusing with views and actions, possibly caused by some weird pause / stop / destroy / create / start / resume state change pattern, and tries to associate the view with the wrong activity. For example, my UM Player view shows album tracks, the system detects a click on the track, but this click is sent to another activity that shows albums on the device and cannot handle the click-back track. The result will be as described in the crash report.

So I'm going to change my application so that both actions have callbacks for each "android :: onClick" and will ignore calls sent to the wrong handler.

Maybe it helps. Any further light in the dark would be much appreciated.

0


source


I had an identical error on the play store. Of course, there is not enough information to quickly point out the problem. FearTheCron's answer made me take a look at my xml for android: onClick instructions. I have 6 assertions and first see no problem, then I noticed that I accidentally created a setOnClickListener for one of them. I haven't seen any problems in my tests on four different phones and tablets over a month of use. I removed the setOnClickListener. I'm not sure if this will fix the problem, but I should have been more careful.

0


source







All Articles