Scala Android AsyncTask не будет вызывать обратный вызов publishProgress, «onProgressUpdate»

#android #scala

#Android #scala

Вопрос:

Я потратил на это слишком много часов и до сих пор продолжал обходиться без функции publishProgress () … к счастью, onPostExecute также выполняется в потоке пользовательского интерфейса, поэтому мне пришлось создать N потоков для каждого изображения, которое я хочу загрузить, вместо одного большого потока, который должен был обновлять listview. Итак, не фатально, но очень неприятно.

Прежде всего, большое спасибо этим страницам за предоставление более подробной информации и способов [ссылка 2!] иметь чистую реализацию Scala…

(1) http://blog.nelsonsilva.eu/2009/10/31/scala-on-android-101-proguard-xmlparser-and-function2asynctask что является обходным путем для: issues.scala-lang.org обзор SI-1459 (новые пользователи ограничены 2 ссылками)

(2) va.eu/2009/10/31/scala-on-android-101-proguard-xmlparser-and-function2asynctask что является обходным путем для: ТО ЖЕ, ЧТО И ВЫШЕ

(3) http://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/docs/android-examples/android-sdk/Wiktionary/src/com/example/android/wiktionary/MyAsyncTask.java?rev=f2fdb3144d0225487cafc7d628adf64889772db4

К сожалению, ни один из них, похоже, не работал для меня на Scala 2.8.1 с Android 2.2.2 под управлением Android-x86 на Virtual box, Ubuntu 11.04.

Вот мой фактический код, мусор удален, только самое необходимое … если кто-нибудь может сказать мне, как вызвать обратный вызов, я буду очень рад, и это еще даже не Рождество. Я потратил часы на это и не могу заставить его работать вообще, я перепробовал все варианты типа «Progress», так как использование AnyRef действительно работает, но любой другой тип не работает как тип «Params», подробности об этом см. (2) выше.

Увы, я получаю preExecute (не показан), doInBackground и postExecute, но обратных вызовов выполнения публикации не видно. 🙁

Код…

 private class FeedLoaderTask(val activity: ActivityFeedReader) 
  extends android.os.AsyncTask[AnyRef, Seq[FeedEntry], Seq[FeedEntry]]
{
  /** @brief dialog to show our progress */
  private var dlgBusy:ProgressDialog = null;


  override def onPreExecute() {
    dlgBusy = ProgressDialog.show(...)
  }

  override protected def doInBackground(params: AnyRef*): Seq[FeedEntry] = {
    // resorted to AnyRef for reasons explained above although
    val url = params.apply(0).asInstanceOf[String]
    log.d("FeedLoaderTask: doInBackground: "   url)
    val feeds = new FeedReader(url).extract
    log.d("Got them, total: "   feeds.length)
    publishProgress()//feeds) // <--- seems to "call" but does not arrive
    feeds
  }

  protected def onProgressUpdate(feeds: Seq[FeedEntry]): Void = {
    // work damn you, WORK!
    log.d("FeedLoaderTask: onProgressUpdate: "   feeds.length)
    return null
  }

  override protected def onPostExecute (feeds: Seq[FeedEntry]) {
    dlgBusy.dismiss()
    dlgBusy = null
    feeds.length match {
    case 0 => messageAndTerminate(R.string.rss_failed_msg)
    case _ =>
      listAdapter = new FeedListAdapter(...)
      activity.setListAdapter(listAdapter)
      ...blah blah more code...
   }
  }
}
  

Итак, у меня есть обходной путь (может быть, даже лучший способ) делать то, что я хочу, но я ненавижу не иметь возможности делать то, что я хочу.

Было бы неплохо решить эту проблему, поскольку она меня победила … это мое первое приложение для Android, и я почти закончил его один раз на Java, но я так устал от всего набора текста и суеты, что начал с нуля и одновременно научился Scala. Я знаю Erlang, LISP и Haskell, так что это помогло. Все, что я могу сказать, это «ИЗУЧАЙТЕ SCALA СЕЙЧАС!»… поддержка XML потрясающая, мой оригинальный код синтаксического анализа RSS (четыре класса!) Теперь находится в одном файле и содержит около 80 строк кода, использующего XML API для поиска элементов, извлечения атрибутов и т. Д.

Всего наилучшего, 🙂

Ответ №1:

Я только что попробовал что-то подобное и, ну, столкнулся с той же проблемой, что и вы. Я решил это с помощью

определение класса как

 class FeedLoaderTask(val activity: ActivityFeedReader)
  extends AsyncTask[AnyRef, AnyRef, Seq[FeedEntry]]
  

и мой onProgressUpdate как:

 override def onProgressUpdate(params: AnyRef*) {
  val feeds = params(0).asInstanceOf[Seq[FeedEnty]]
  ...
}
  

Как вы можете видеть, это похоже на метод doInBackground() (обратите внимание, что вам не обязательно явно вызывать apply() в Scala, а методы void не требуют объявления возвращаемого типа и «=»).

Ответ №2:

защищенное переопределение onProgressUpdate(прогресс: Seq[FeedEntry] *) { }

Вероятно, вы хотите указать свою AsyncTask как AsyncTask[AnyRef, FeedEntry, Seq[FeedEntry]]

Итак, вы можете сделать

защищенное переопределение onProgressUpdate (каналы: FeedEntry *)

вместо

Ответ №3:

Полезно выполнить преобразование между аргументами и …. Создав новый класс Java, который смешивает оба, я мог бы добиться результата:

 import scala.collection.mutable.ArrayBuffer;
import android.os.AsyncTask;

public abstract class MyAsyncTask<U, V, W> extends AsyncTask<U, V, W> {

    @Override
    protected W doInBackground(U ... args) {
        int count = args.length;
        ArrayBuffer<U> res = new ArrayBuffer<U>(count);
        for (int i = 0; i < count; i  ) {
          res.$plus$eq(args[i]);
        }
        return doInBackground1(res);
    }

    // Method to override in the scala file
    protected abstract W doInBackground1(ArrayBuffer<U> args);

    ArrayBuffer<V> res = new ArrayBuffer<V>();

    @Override
    protected void onProgressUpdate(V ... args) {
      int count = args.length;
      res.ensureSize(count);
      res.clear();

      ArrayBuffer<V> res = new ArrayBuffer<V>(count);
      for (int i = 0; i < count; i  ) {
        res.$plus$eq(args[i]);
      }
      onProgressUpdate1(res);
   }

   // Method to override in the scala file
   protected abstract void onProgressUpdate1(ArrayBuffer<V> args);
}