In an Android project I tried using the Java 8's new lambda feature so I modified an existing functioning anonymous inner class into lambda. However, the app crashes when the code is executed with the following error message:
11-25 11:20:33.485 27105-27105/com.infor.Dashboards.dev E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.infor.Dashboards.dev, PID: 27105
java.lang.VerifyError: Verifier rejected class com.infor.Dashboards.Settings.DebugTestingFragment$3$1$$Lambda$-void_onPostExecute_java_lang_String_string_LambdaImpl0 due to bad method void com.infor.Dashboards.Settings.DebugTestingFragment$3$1$$Lambda$-void_onPostExecute_java_lang_String_string_LambdaImpl0.processMessage(android.os.Message) (declaration of 'com.infor.Dashboards.Settings.DebugTestingFragment$3$1$$Lambda$-void_onPostExecute_java_lang_String_string_LambdaImpl0' appears in /data/app/com.infor.Dashboards.dev-1/base.apk)
at com.infor.Dashboards.Settings.DebugTestingFragment$3$1.onPostExecute(DebugTestingFragment.java:308)
at com.infor.Dashboards.Settings.DebugTestingFragment$3$1.onPostExecute(DebugTestingFragment.java:304)
at android.os.AsyncTask.finish(AsyncTask.java:651)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5460)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Here is the sample code (app crashes when the button is clicked):
view.findViewById(R.id.test_code).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AsyncTask<Void, Void, String>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(String string) {
super.onPostExecute(string);
ApplicationState.PAUSE_HANDLER.sendMessage(new Message(), message -> {
Logger.LogDebug(string + " " + v.getId());
}, "test");
}
@Override
protected String doInBackground(Void... params) {
return "test";
}
}.execute((Void) null);
}
});
I managed finding out the problem is the lambda accesses the "v" variable holding the View given as an argument by the onClick() method. Changing it to "final" didn't have any effect. However, when it is copied just above the lambda, it works:
view.findViewById(R.id.test_code).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AsyncTask<Void, Void, String>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(String string) {
super.onPostExecute(string);
View v1 = v;
ApplicationState.PAUSE_HANDLER.sendMessage(new Message(), message -> {
Logger.LogDebug(string + " " + v1.getId());
}, "test");
}
@Override
protected String doInBackground(Void... params) {
return "test";
}
}.execute((Void) null);
}
});
The questions are:
- What is wrong here? Am I doing anything illegal?
- Is there any way to find the generated lambda code? I tried decompiling the APK, found out some weird .Lambda classes being instantiated, but don't know where to find their code. Maybe that could help figuring out what is going on.