Оптимальный способ отложить на событие? - PullRequest
6 голосов
/ 30 марта 2012

В моем небольшом приложении я получаю серию очередей onEventXXX () из системы (не контролируемых мной).

Время этих onEventXXX () не гарантируется.Гарантируется только то, что они получены в порядке , в котором они были помещены в очередь.

Внутри onEventXXX () мне нужно запустить операцию (O), которая не может запуститься, пока другой процесс (P) продолжается.

Но я не могу просто отказаться от этого "запуска операции (O)".Я должен ждать, пока этот процесс (P) не завершится, , затем запустить его.

Итак, я должен поставить в очередь или, по крайней мере, отложить этот «запуск операции» до этого процесса (P)завершено.

Моя непосредственная идея для реализации этого состояла в том, что вместо запуска операции (O) я бы:

  1. Запустил таймер с одним выстрелом, который периодически проверял быпроцесс (P)
  2. Когда истекает время таймера, если процесс (P) не завершен, запустите время (само) снова.
  3. Когда истекает время таймера, если процесс (P) завершен,пожарная операция (O).

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

Если естьлучший способ реализовать вышесказанное, что бы это было?

Ответы [ 3 ]

3 голосов
/ 06 апреля 2012

CountDownLatch будет лучшим решением.

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

Процесс как ниже

  1. определить переменную CountDownLatch с именем latch
  2. установить количество защелок на 1
  3. когда получено событие O, создайте новый ThreadO. в ThreadO дождитесь, пока счетчик защелок не достигнет 0.
  4. когда процесс P завершится, отсчет обратного отсчета.

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

  1. если O получен первым, вы можете подождать, пока P не завершится.
  2. если P получен первым, вы можете немедленно начать O.
  3. вы можете использовать функцию тайм-аута, предоставляемую CountDownLatch.

Я использую CountDownLatch в модульном тесте asyc. Вы можете увидеть мой код здесь: http://kingori.egloos.com/4554640

Хотя это не похоже на ваш случай, но вы можете получить подсказку из моего кода. Также хороший пример - Javadoc CountDownLatch.

3 голосов
/ 02 апреля 2012

Я бы сделал это следующим образом:

  • в onEventX, проверьте, завершился ли процесс, если да, выполните ваши действия немедленно (вы также можете пропустить этот шаг и просто выполнить 2-й шаг)

  • в противном случае создайте AsyncTask, где вы вызываете Process.waitfor () в doInBackground, когда он завершится, выполните действие в onPostExecute

подход, вы вызываете действие в потоке пользовательского интерфейса, и как можно скорее.

Не используйте таймеры для этой задачи.Таймер - это метод опроса.Если ваш таймер будет работать слишком быстро, вы просто потратите время процессора.Если тикает слишком медленно, ваше действие будет вызвано с возможной задержкой.

2 голосов
/ 05 апреля 2012

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

Теперь для самого действия, если существует только одно (или несколько) таких возможных действий, которые происходят после одного (или нескольких) возможных фоновых процессов, у меня будет кнопка синхронно поднять флаг (возможно, через постоянный член класса) и выполнить длинный процесс синхронно для проверки этого флага после его завершения и выполнения запрошенного действия по окончании.

Другой возможный вариант, если использовать ожидание и уведомление, чтобы код кнопки ожидал завершения процесса, это обычно считается очень высокопроизводительным решением в Java: например,

(игнорируйте опечатки, это на-spot):

button.setOnClickListener(new OnClickListener() { 
    public void onClick(View v) {
        v.post(new Runnable() {
            @Override
            public void run() {
                synchronized (lockObject) {
                    try {
                        lockObject.wait();
                        doAction();
                    } catch (InterruptedException e) {}
                }
            }
        }
    }
}

Затем завершите длинный процесс notify.

Обратите внимание, что new Runnable() не создает новый поток, он просто добавляет Runnable в очередь потоков View

Как подсказывают мыши, обработчик кнопки onClickследует проверить, не запущен ли в данный момент процесс, и если это так, просто выполнить действие немедленно.

Таким образом, вам не нужно создавать новый поток (или AsyncTask, который фактически является пулом потоков)

...