Ожидание выполнения 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
цикл.