Поддержание временного разрыва с помощью post vs postDelayed

Есть две функции, которые мне нужно запустить с минимальным промежутком времени между ними. По причинам, выходящим за рамки этого вопроса, сначала я пытался контролировать время процесса, работающего в веб-просмотре (через JavascriptInterface):

webView.post(() -> functionA());
// ... wait 2 secs in javascript and then...
webView.post(() -> functionB());

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

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

Итак, если это так, то моя новая стратегия состоит в том, чтобы забыть об управлении временем из javascript, работающего в веб-просмотре, и просто управлять им непосредственно в Java.

Итак, вопрос в том... гарантирует ли использование postDelayed() следующим образом хотя бы минимальный промежуток времени между двумя запущенными функциями?

webView.post(() -> functionA());
webView.postDelayed(() -> functionB(), 2000);

Я чувствую, что это должно иметь желаемый эффект, но я опасаюсь, что, возможно, это равнозначно тому, что я делал... помещая functionB в очередь через 2 секунды после functionA, без гарантии того, что они действительно сохранят этот временной интервал. между ними


person drmrbrewer    schedule 28.03.2020    source источник
comment
Я использовал PostDelayed, и да, это работает.   -  person Rajen Raiyarela    schedule 01.04.2020
comment
не могли бы вы подождать, пока функция A что-то вернет или выполнится (установив какой-то флаг), и только после этого начать ждать две секунды. или даже поместить функцию B внутри функции A с задержкой   -  person quealegriamasalegre    schedule 01.04.2020
comment
Это вопрос WebView/JavaScript или это вопрос Java?   -  person Basil Bourque    schedule 04.04.2020
comment
Вы ищете промежуток в 2 секунды после того, как functionA() вернулся или после того, как functionA() начал выполняться?   -  person tynn    schedule 04.04.2020


Ответы (2)


Что делают post() и postDelayed(), так это то, что они добавляют Message в MessageQueue, который Looper зацикливается. Таким образом, действие внутри post() не будет выполняться синхронно, вместо этого оно будет выполнено в более поздний момент времени.

webView.post(() -> functionA()) приведет к добавлению действия, которое будет запущено через какое-то время в будущем, когда webView передаст свои measure-layout-draw методы. Для примера предположим, что это займет 15 мс.

webView.postDelayed(() -> functionB(), 2000) приведет к добавлению действия, которое будет выполняться примерно через 2 секунды, начиная с этого момента. Таким образом, на самом деле не гарантируется, что functionA и functionB будут вызываться с интервалом 2000 мс (и, скорее всего, так и будет), потому что functionA() был выполнен в "сейчас + 15", тогда как functionB() было выполнено в "сейчас + 2000".

Вместо этого, если у вас есть это строгое требование, возможно, вместо использования postDelayed() вам следует использовать один из postAtTime() перегружает?

Рассмотрим подход: выполнить webView.post(() -> functionA()) и внутри functionA() запланировать запуск нового исполняемого объекта в 2000-х как таковой Handler().postDelayed(2000, someRunnable). Я думаю, что это может быть рабочим подходом для вашего варианта использования.

person azizbekian    schedule 02.04.2020
comment
Итак, если выполнение functionA() действительно задерживается, все еще возможно, что functionA() будет выполнено сейчас + 1999, тогда как functionB() выполняется сейчас + 2000? В теории? И да, я на самом деле сейчас использую подход, который вы предлагаете, а именно вызов functionB() из functionA()... Мне все еще было любопытно узнать ответ на вопрос. - person drmrbrewer; 02.04.2020
comment
Если MessageQueue заполнен другими сообщениями до functionA() и пуст после functionA(), то теоретически да, это возможно (не уверен в этом, просто делаю вывод, основанный на принципах работы этих компонентов). Честно говоря, я не понимаю, как это возможно в реальном мире. - person azizbekian; 02.04.2020

Не уверен, что вы хотите задать вопрос о Java или вопрос о JavaScript.

Платформа Java Executors

Если Java, решение простое. Java предоставляет платформу Executors для запуска задач в потоках. Это включает в себя планирование задач для запуска после первоначальной задержки. (См. руководство от Oracle.)

Чтобы пара задач выполнялась с временным интервалом между ними, запланируйте немедленный запуск первой из них. Затем в той же запланированной службе исполнителя запланируйте запуск второй задачи после задержки.

Пример

Определите свои задачи как Runnable или Callable объектов.

Runnable task = 
    () -> { 
        System.out.println( "Task is running. " + Instant.now() ); 
    }
;

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

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ;

Расписание каждой из ваших задач.

В этом примере мы запускаем первую задачу сразу в фоновом потоке.

ses.schedule( task1 , 0 , TimeUnit.SECONDS ) ;  // Runs immediately, in the background on another thread. 

Вторая задача начнется примерно через 45 секунд, также в фоновом потоке.

ses.schedule(               // Tell the executor what you want to run, and when you want it run on your behalf in a background thread.
    task2 ,                 // Define task to be executed as a `Runnable`.
    45 ,                    // Count of time to wait.
    TimeUnit.SECONDS        // Specify the granularity of time used in previous argument.
) ; 

Перехватывать исключения

Совет: Обязательно оберните работу в своей задаче с помощью общего try-catch. Если какое-либо неперехваченное исключение (или ошибка) доходит до службы-исполнителя, служба останавливается. Любые будущие запланированные задачи не будут выполняться. Это происходит молча. Для получения дополнительной информации см. мой ответ на соответствующий вопрос.

Закройте пул потоков

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

Утилиты Jakarta Concurrency

Если вы создаете веб-приложение, ваш сервер приложений Jakarta EE может поддерживать Jakarta Concurrency для дальнейшего упрощения этого кодирования и автоматического отключения резервного пула потоков службы-исполнителя.

person Basil Bourque    schedule 04.04.2020