Ожидание завершения 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();
}
И как то так с другой Runnable
s' 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
а не Thread
s? Если вы используете Thread
s, вы можете использовать различные примитивы связи потоков, которые существуют именно по этой причине (wait()
а также join()
особенно).