简体   繁体   中英

AsyncTask.doInBackground - abstract method not implemented error in Android Scala project

Can anyone give me any clues on how to debug the following.

I have a mixed java / scala android project that I'm working on in Intellij and I process it through Proguard as part of run config.

When I run the app I get the error:

07-24 12:36:35.879  21731-21779/com.ovaphone E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1
java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:299)
        at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
        at java.util.concurrent.FutureTask.run(FutureTask.java:137)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
        at java.lang.Thread.run(Thread.java:856)
 Caused by: java.lang.AbstractMethodError: abstract method not implemented
        at android.os.AsyncTask.doInBackground(AsyncTask.java)
        at android.os.AsyncTask$2.call(AsyncTask.java:287)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)

I'm guessing it's caused by Proguard stripping out too much.

I do have one class that extends AsyncTask, and I know this class is definitely the culprit as when I comment out its use the problem disappears.

My AsyncTask is:

object CheckNetworkStatusOnStartup {
  class Payload(var mainActivity: MainActivity) {
    var isConnected: java.lang.Boolean = false
  }

}

class CheckNetworkStatusOnStartup extends AsyncTask[CheckNetworkStatusOnStartup.Payload, Void, CheckNetworkStatusOnStartup.Payload] {

 override def doInBackground(params: Payload*): Payload = {
      val payload = params(0)
      <checks the network status and sets Payload.isConnected>
      payload
  }

 override def onPostExecute(payload: Payload) {
      <updates network status on screen of MainActivity>
  }

}

And it's called in the MainActivity by:

 new CheckNetworkStatusOnStartup().execute(new CheckNetworkStatusOnStartup.Payload(this))

I've tried adding both:

-keep class * extends android.os.AsyncTask {
  *;
}

and

-keep public class com.mypackage.MyClass extends android.os.AsyncTask

to the proguard config file but neither make a difference.

Should those '-keep' statements be sufficient?

Can anyone give me any pointers on how to proceed?

Edit

Following Eric's suggestion, running javap on the compiled class gives the following output:

public class com.ovaphone.CheckNetworkStatusOnStartup extends android.os.AsyncTask<com.ovaphone.Payload, java.lang.Void, com.ovaphone.Payload> {
  public com.ovaphone.Payload doInBackground(scala.collection.Seq<com.ovaphone.Payload>);
  public void onPostExecute(com.ovaphone.Payload);
  public com.ovaphone.Payload doInBackground(com.ovaphone.Payload[]);
  public void onPostExecute(java.lang.Object);
  public com.ovaphone.CheckNetworkStatusOnStartup();

}

Running dexdump on the process apk shows that doInBackground is missing (but onPastExecute is not).

To investigate if problem was being caused by the interaction between Proguard and Scala, I wrote java version of the code (I've just noticed it's slightly different, in that Payload is an inner class of CheckNetworkStatusOnStartup, but I don't think that is significant). The java version works fine! Here's the javap output:

class com.mysimplet.CheckNetworkStatusOnStartup extends android.os.AsyncTask<com.mysimplet.CheckNetworkStatusOnStartup$Payload, java.lang.Void, com.mysimplet.CheckNetworkStatusOnStartup$Payload> {
  com.mysimplet.CheckNetworkStatusOnStartup();
  protected com.mysimplet.CheckNetworkStatusOnStartup$Payload doInBackground(com.mysimplet.CheckNetworkStatusOnStartup$Payload...);
  protected void onPostExecute(com.mysimplet.CheckNetworkStatusOnStartup$Payload);
  protected void onPostExecute(java.lang.Object);
  protected java.lang.Object doInBackground(java.lang.Object...);
}

Notice the difference between the method definitions for doInBackground:

Scala: public com.ovaphone.Payload doInBackground(scala.collection.Seq<com.ovaphone.Payload>);

vs

Java: protected com.ovpahone.Payload doInBackground(com.ovaphone.Payload...);

So, Scala has transformed the varargs into a Seq. Maybe that's confusing Proguard? Anyone any ideas?

As a workaround, I've included the java version of the class in my project, but it would be nice to get the Scala version working soon.

This may help.

http://piotrbuda.eu/2012/12/scala-and-android-asynctask-implementation-problem.html

Signature issue I'd hazard a guess.

Just had the same problem myself, changing the signature resolved the issue for me.

You should make sure that ProGuard gets a suitable Android runtime (android.jar). Depending on your build process, it is added automatically (eg Android Ant, Gradle, Eclipse) or you have to add it yourself with the option -libraryjars (eg custom build).

Note that you can see which configuration ProGuard is applying with

-printconfiguration config.txt

You should then check the -injars and -libraryjars options.

Without the proper runtime jar, ProGuard generally prints out many warnings and by default refuses to continue. It needs the runtime classes to analyze the structure of the application. In this case, for instance, it needs to know the runtime interface methods, so it doesn't remove them from your implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM