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

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

В отдельных действиях 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();

В моей RunAnable OtherActivity:

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 [email protected] that was originally added here
01-10 15:41:25.543: E/WindowManager(7074): android.view.WindowLeaked: Activity com.myapp.MainActivity has leaked window [email protected] that was originally added here

Ответы

Ответ 1

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

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

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

private boolean listsDone = false;

boolean getListsDone() {
    return listsDone;
}

И что-то вроде этого с его методом run(), сразу после создания списков:

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

И что-то вроде этого другим методам Runnable s 'run(), в тот момент, когда они должны ждать:

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

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

Ответ 2

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

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

  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", одновременно очищая любой код, который у них есть, для ожиданий и соединений.

Ответ 3

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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