AsyncTask.doInBackground - Android Scala 项目中的抽象方法未实现错误

Posted

技术标签:

【中文标题】AsyncTask.doInBackground - Android Scala 项目中的抽象方法未实现错误【英文标题】:AsyncTask.doInBackground - abstract method not implemented error in Android Scala project 【发布时间】:2014-09-16 00:38:40 【问题描述】:

谁能给我任何关于如何调试以下内容的线索。

我在 Intellij 中有一个混合的 java / scala android 项目,我通过 Proguard 处理它作为运行配置的一部分。

当我运行应用程序时出现错误:

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)

我猜这是Proguard剥离太多造成的。

我确实有一个扩展 AsyncTask 的类,我知道这个类绝对是罪魁祸首,因为当我注释掉它的使用时,问题就消失了。

我的 AsyncTask 是:

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

类 CheckNetworkStatusOnStartup 扩展 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>
  

它在 MainActivity 中被调用:

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

我都试过了:

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

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

到 proguard 配置文件,但两者都没有区别。

那些“-keep”语句就足够了吗?

谁能给我任何关于如何进行的指示?

编辑

按照 Eric 的建议,在编译后的类上运行 javap 会得到以下输出:

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();

在进程 apk 上运行 dexdump 显示缺少 doInBackground(但 onPastExecute 没有)。

为了调查问题是否是由 Proguard 和 Scala 之间的交互引起的,我编写了 Java 版本的代码(我刚刚注意到它略有不同,因为 Payload 是 CheckNetworkStatusOnStartup 的内部类,但我没有认为这很重要)。 java版本运行良好!这是 javap 的输出:

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...);

注意 doInBackground 的方法定义之间的区别:

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

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

因此,Scala 已将可变参数转换为 Seq。也许这让 Proguard 感到困惑?有人有什么想法吗?

作为一种解决方法,我已经在我的项目中包含了该类的 java 版本,但如果 Scala 版本能够尽快运行,那就太好了。

【问题讨论】:

你的 AsyncTask 是什么样子的,能贴出代码吗? 当然 - 有点长,你想看全部还是只看定义? 我已经添加了一个总结版本,希望这就足够了。我认为整个代码会污染线程。谢谢你的帮助,顺便说一句。 没问题,我认为您需要像使用 onPostExecute 一样覆盖 doInBackground。 好地方!但是,只是添加了它,它似乎没有任何区别。我会更新帖子。 【参考方案1】:

这可能会有所帮助。

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

签名问题我冒险猜测。

我自己也遇到了同样的问题,更改签名为我解决了问题。

【讨论】:

对于 Scala 2.11,我们似乎也不得不更改返回类型的签名。这意味着我们必须使用doInBackground(p1: AnyRef*): AnyRef,而不是doInBackground(p1: AnyRef*): String【参考方案2】:

您应该确保 ProGuard 获得合适的 Android 运行时 (android.jar)。根据您的构建过程,它会自动添加(例如 Android Ant、Gradle、Eclipse),或者您必须使用选项 -libraryjars 自行添加(例如自定义构建)。

请注意,您可以查看 ProGuard 应用的配置

-printconfiguration config.txt

然后您应该检查-injars-libraryjars 选项。

如果没有正确的运行时 jar,ProGuard 通常会打印出许多警告,并且默认情况下会拒绝继续。它需要运行时类来分析应用程序的结构。例如,在这种情况下,它需要知道运行时接口方法,因此它不会从您的实现中删除它们。

【讨论】:

感谢您的建议。我没有在配置文件中明确指定 android.jar,但是使用“-printconfiguration config.txt”,我看到构建过程会自动添加到正确的文件中(-libraryjars /Applications/android-sdk/platforms/android -17/android.jar)。 您可以使用javap 检查您的AsyncTask 实现的编译类文件是否具有doInBackground 的实现以及运行时中指定的正确签名。您可以使用dexdump 检查处理后的 apk 文件中是否仍然如此。 输出确实很有用:Java 版本具有所需的实现java.lang.Object doInBackground(java.lang.Object...),但 Scala 版本没有。注意确切的签名;其他 doInBackground 方法不算在内。在 ProGuard 处理代码之前问题就存在了。您应该考虑从 Scala 编译器中获取正确的签名。 @DamianHelme 除了编写你的 AsyncTask 的 java 版本之外,你有没有找到任何解决方案? @aga 抱歉,时间压力把我的注意力转移到了其他地方,最后我把 AsyncTask 留在了 java 中。我在 Scala-user 上创建了这个帖子:groups.google.com/forum/#!searchin/scala-user/asynctask/…,讨论有了一点进展。

以上是关于AsyncTask.doInBackground - Android Scala 项目中的抽象方法未实现错误的主要内容,如果未能解决你的问题,请参考以下文章

AsyncTask doInBackground方法未调用

AsyncTask.doInBackground 在 2.3 上没有被调用,在 4.0+ 上工作

AsyncTask.doInBackground - Android Scala 项目中的抽象方法未实现错误

AsyncTask doInBackground 返回数组列表

AsyncTask doInBackground 仅有时返回空指针异常

在 AsyncTask doInBackground() 中修改视图不会(总是)抛出异常