Ожидание завершения Runnable перед запуском другого Runnable

У меня есть приложение Android с основной вкладкой и несколькими действиями на отдельных вкладках. В onCreate() моей основной деятельности у меня есть исполняемый файл, который создает список, а в отдельных действиях я использую этот список.

В onCreate() отдельных действий у меня также есть Runnables, которые работают со списком. Однако мне нужно, чтобы эти Runnables запускались только тогда, когда Runnable действия основной вкладки завершает создание списка, иначе я бы получил нулевой список. Я пытаюсь найти элегантный способ сделать это. Прямо сейчас в Runnable моей основной деятельности я устанавливаю глобальную логическую переменную isDone, а в Runnable моей индивидуальной активности я жду, чтобы isDone был установлен через цикл while. Это работает, но, вероятно, не лучший способ сделать это.

Какие-нибудь мысли?

Благодарю.

Изменить: я пытаюсь следующий код, но я получаю ошибки во время выполнения:

В моем MainActivity Runnable:

mainRunnable = new Runnable() {
  public void run() {
    try {
      generateList();
      synchronized(this) {
      listDone = true;
      notifyAll();
    }
  } catch (Exception e) {
      Log.e("BACKGROUND_PROC", e.getMessage());
    }
  }
};
Thread thread = new Thread(null, mainRunnable, "Background");
thread.start();

В моем OtherActivity Runnable:

otherRunnable = new Runnable() {
  public void run() {
    synchronized(MainActivity.mainRunnable) {
      if (!MainActivity.getListDone()) {
        try {
          wait();
        } catch (InterruptedException e) {
        }
      }
    }
  }
};
Thread thread = new Thread(null, otherRunnable, "Background");
thread.start();

Кажется, что mainRunnable работает полностью, но, похоже, otherRunnable вызывает сбой приложения. Я получаю следующее сообщение об ошибке:

01-10 15:41:25.543: E/WindowManager(7074): Activity com.myapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@40539850 that was originally added here
01-10 15:41:25.543: E/WindowManager(7074): android.view.WindowLeaked: Activity com.myapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@40539850 that was originally added here

7 ответов

Решение

Вы можете использовать wait а также notify методы.

Чтобы сделать это, должен быть какой-то глобально доступный объект, чья блокировка в данный момент не используется ничем другим в программе. Я предполагаю, что создание списка Runnable Сам может сыграть эту роль.

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

private boolean listsDone = false;

boolean getListsDone() {
    return listsDone;
}

И как то так run() Метод, сразу после того, как он завершил создание списков:

synchronized (this) {
    listsDone = true;
    notifyAll();
}

И как то так с другой Runnables' run() методы, в точке, где они должны ждать:

synchronized (listCreatingRunnableObject) {
    if (!listCreatingRunnableObject.getListsDone()) {
        try {
            listCreatingRunnableObject.wait();
        } catch (InterruptedException e) {
            // handle it somehow
        }
    }
}

Обновление: чтобы уточнить, оба synchronized блоки должны быть синхронизированы по одному и тому же объекту, и вы должны вызвать wait() а также notifyAll() на этом объекте. Если объект является Runnableтогда он может быть неявным для первого (как в приведенном выше коде), но если это действие, вам нужно явно использовать объект действия в обоих случаях.

Вы можете использовать Queue как это:

public class RunQueue implemements Runnable
{
  private List list = new ArrayList();

  public void queue(Runnable task)
  {
    list.add(task);
  }

  public void run()
  {
    while(list.size() > 0)
    {
      Runnable task = list.get(0);

      list.remove(0);
      task.run();
    } 
  }
}

Это позволяет использовать один поток, а не несколько потоков. И вы можете поддерживать все существующие объекты "Runnable", одновременно очищая любой код, который у них есть, для ожиданий и соединений.

Установите CountDownLatch со значением 1 в главном потоке, а затем подождите, пока зависимые потоки его не дождутся. Когда основная нить завершена, вы отсчитываете защелку до 0, и официанты начнут прямо вверх.

Активное ожидание с использованием while петля не очень хорошая идея. Самым простым для первого Runnable было бы просто запустить остальных из них, как свой последний шаг. Если по какой-то причине это не сработает, посмотрите на публикацию сообщения в обработчике.

Может быть, вы можете сослаться на Looper в Android. Проще говоря, thead продолжает выполнять задачу из очереди в while петля.

Я создал вспомогательный метод, который содержит весь шаблонный код для публикации исполняемого файла и ожидания его завершения.

Логика похожа на то, что описывает @Taymon, но реализация более общая.

Проверьте это: https://gist.github.com/Petrakeas/ce745536d8cbae0f0761

Есть ли причина, по которой вы используете Runnableа не Threads? Если вы используете Threads, вы можете использовать различные примитивы связи потоков, которые существуют именно по этой причине (wait() а также join() особенно).

Другие вопросы по тегам