Как организовать длительные (длительные) действия на Android?

Например, мы находимся в SomeActivity, и в действии есть кнопка, которая вызывает перемещение файлов из одного каталога в другой (позвольте ему выполнить задание).

В BlackBerry я бы:

  • нажмите всплывающее окно с отменой отмены (диалоговое окно), в котором говорится: "Пожалуйста, подождите..."
  • запустить поток, который выполняет задание
  • при завершении потока закрыть всплывающее окно

Этот подход 99,99% может гарантировать, что мы останемся на том же экране после завершения задачи, пользователь просто увидит всплывающее окно и ждет завершения работы. Вращение устройства или что-то другое не прерывает желаемый рабочий процесс.

На Android все меняется. Я знаю, что AsyncTask, вероятно, предоставляется для решения моего дела. Там даже хороший пример того, как он должен использоваться. Но так как нет гарантии того, как долго экземпляр Activity будет жить, AsyncTask должен быть отменен onSaveInstanceState (и перезапущен на onRestoreInstanceState). Это означает, что использование AsyncTask не гарантирует, что мы сможем полностью выполнить задание после его запуска. В некоторых случаях при отправке запроса на отправку HTTP для создания пользователя я бы не захотел войти в проблему "пользователь уже существует для этого входа" при повторном запуске AsyncTask. Это возможно, так как AsyncTask может быть прерван, пока запрос уже отправлен (и сервер фактически выполняет свою работу - создание нового пользователя), но AsyncTask отменяется, прежде чем мы получим ответ.

Есть ли какое-либо решение на Android для того, чтобы получить описанное выше BB-поведение?

Ответ 1

В мае 2010 года Google выпустил новый сеанс ввода-вывода под названием Разработка клиентских приложений REST для Android, в котором объясняется, как добиться именно того, что я просил.

Оказалось, что вопрос довольно сложный, поэтому нет простого и быстрого решения. Решение требует глубокого знания платформы Android/API. Это цена, вызванная гибкостью процесса приложения/жизненного цикла деятельности.

Я чувствую некоторую странность в том, почему эта информация не была представлена ​​с самой первой версии Android. Похоже, Google знал, как писать 100% -ные приложения без ошибок, и по какой-то маркетинговой причине не разделял подход. Только представьте, сколько багги было написано в мае 2010 года.

В любом случае я рад, что у меня есть что-то, что мы называем передовой практикой.

Ответ 2

Но поскольку нет никаких гарантий того, как длинный экземпляр Activity будет жить AsyncTask следует отменить на onSaveInstanceState (и перезапущен onRestoreInstanceState).

Или управлять им с помощью Service.

Ответ 3

Если ваша активность хочет остаться на экране, вы можете просто начать Thread следующим образом:

final File fromFile = ...;
final File toFile = ...;

new Thread() {
    @Override
    public void run() {
      // do something with fromFile, toFile
    }
}.start();

Таким образом, GUI-Thread готов к работе, другие думают, что отображают

  android.app.ProgressDialog

Кроме того, подумайте о том, чтобы сделать диалог Невозможным с помощью

  ProgressDialog.setCancelable(false);

Таким образом, пользователь может выйти только через HOME-Key, о котором вы узнаете, когда

  Activity.onPause()

. Более того, вы можете захотеть заглянуть в Вакелокс, чтобы экран не стал черным, и ваше приложение было нажато в фоновом режиме, где его можно было убить. Вы бы сделали это в теме:

  PowerManager pm = (PowerManager) ivContext.getSystemService(Context.POWER_SERVICE);
  Wakelock wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyApp");
  wakeLock.acquire();

  // ... copy stuff ...

  wakeLock.release();

Конечно, вам придется выпустить wakeLock, когда пользователь уйдет с помощью HOME-Key.

Наконец, если вы хотите вызвать GUI-Elements из фонового потока, это будет работать, только если поток является частью GUI-Event-Loop, как обычный поток, в котором вы работаете, при вызове...- методы. Для этого ваш фоновый поток будет иметь обратный вызов в GUI-Thread через обработчик. Вот так:

  private Handler mHandler = new Handler() { 
      @Override
      public void handleMessage(Message msg) {
          Log.v(TAG, "Got Message "+msg.what); // prints: Got Message 77
      // ... do GUI actions ...
      }    
  };

  // ... in Thread ...

  int lvInfo = 77;
  mHandler.sendEmptyMessage(lvInfo);

Вы можете даже помещать объекты в сообщение так:

  Message txtMsg = Message.obtain();
  textMsg.obj = "Hello World";
  mHandler.sendMessage(lvTextMsg);