5.5.6. Фоновые задачи
Механизм фоновых задач предназначен для асинхронного выполнения длительных операций на клиентском уровне без заморозки пользовательского интерфейса.
Использование фоновых задач:
-
Задача описывается как наследник абстрактного класса
BackgroundTask
. В конструктор задачи необходимо передать ссылку на контроллер экрана, с которым будет связана задача, и значение таймаута ее выполнения.Если экран указан, то при его закрытии пользователем активная задача будет прервана. Кроме того, задача будет автоматически прервана по истечении указанного таймаута.
Собственно действия, выполняемые задачей, реализуются в методе run().
-
Создается объект управления задачей −
BackgroundTaskHandler
. Для этого экземпляр задачи необходимо передать методуhandle()
бинаBackgroundWorker
. Ссылку наBackgroundWorker
можно получить инжекцией в контроллер экрана, либо статическим методом классаAppBeans
. -
Выполняется запуск задачи.
Warning
|
Метод |
Пример:
@Inject
protected BackgroundWorker backgroundWorker;
@Override
public void init(Map<String, Object> params) {
// Create task with 10 sec timeout and this screen as owner
BackgroundTask<Integer, Void> task = new BackgroundTask<Integer, Void>(10, this) {
@Override
public Void run(TaskLifeCycle<Integer> taskLifeCycle) throws Exception {
// Do something in background thread
for (int i = 0; i < 5; i++) {
TimeUnit.SECONDS.sleep(1); // time consuming computations
taskLifeCycle.publish(i); // publish current progress to show it in progress() method
}
return null;
}
@Override
public void canceled() {
// Do something in UI thread if the task is canceled
}
@Override
public void done(Void result) {
// Do something in UI thread when the task is done
}
@Override
public void progress(List<Integer> changes) {
// Show current progress in UI thread
}
};
// Get task handler object and run the task
BackgroundTaskHandler taskHandler = backgroundWorker.handle(task);
taskHandler.execute();
}
Подробная информация о назначении методов приведена в JavaDocs классов BackgroundTask
, TaskLifeCycle
, BackgroundTaskHandler
.
Ниже приведены моменты, на которые следует обратить внимание:
-
BackgroundTask<T, V>
− параметризованный класс:-
T
− тип объектов, показывающих прогресс задачи. Объекты этого типа передаются в методprogress()
задачи при вызовеTaskLifeCycle.publish()
в рабочем потоке. -
V
− тип результата задачи, он передается в методdone()
. Его также можно получить вызовом методаBackgroundTaskHandler.getResult()
, что приведет к ожиданию завершения задачи.
-
-
Метод
canceled()
вызывается только в случае управляемой отмены задачи, то есть при вызовеcancel()
уTaskHandler
. -
Метод
handleTimeoutException()
вызывается при истечении таймаута задачи. Если окно, в котором выполняется задача, закрывается, то задача останавливается без оповещения.
-
Метод
run()
задачи должен поддерживать возможность прерывания извне. Для этого в долгих процессах желательно периодически проверять флагTaskLifeCycle.isInterrupted()
, и соответственно завершать выполнение. Кроме того, нельзя тихо проглатывать исключениеInterruptedException
(или вообще все исключения). Вместо этого нужно либо вообще не перехватывать его, либо выполнять корректный выход из метода.-
Метод
isCancelled()
возвращаетtrue
, если задача была прервана вызовом методаcancel()
.public String run(TaskLifeCycle<Integer> taskLifeCycle) { for (int i = 0; i < 9_000_000; i++) { if (taskLifeCycle.isCancelled()) { log.info(" >>> Task was cancelled"); break; } else { log.info(" >>> Task is working: iteration #" + i); } } return "Done"; }
-
-
Объекты
BackgroundTask
не имеют состояния. Если при реализации конкретного класса задачи не заводить полей для хранения промежуточных данных, то можно запускать несколько параллельно работающих процессов, используя единственный экземпляр задачи. -
Объект
BackgroundHandler
можно запускать (т.е. вызывать его методexecute()
) всего один раз. Если требуется частый перезапуск задачи, то используйте классBackgroundTaskWrapper
. -
Для показа пользователю модального окна с прогрессом и кнопкой Отмена используйте классы
BackgroundWorkWindow
илиBackgroundWorkProgressWindow
с набором статических методов.Для окна можно задать режим отображения прогресса и разрешить или запретить отмену фоновой задачи. -
Если внутри потока задачи необходимо использовать некоторые значения визуальных компонентов, то нужно реализовать их получение в методе
getParams()
, который выполняется в потоке UI один раз при запуске задачи. В методе run() эти параметры будут доступны через методgetParams()
объектаTaskLifeCycle
. -
При возникновении исключительных ситуаций в потоке UI вызывается метод
BackgroundTask.handleException()
, в котором можно отобразить ошибку. -
На выполнение фоновых задач влияют свойства приложения cuba.backgroundWorker.maxActiveTasksCount и cuba.backgroundWorker.timeoutCheckInterval.
Warning
|
В блоке Web Client фоновые задачи используют технологию HTTP push, предоставляемую фреймворком Vaadin. См. https://vaadin.com/wiki/-/wiki/Main/Working+around+push+issues для получения информации о настройке веб-серверов для использования данной технологии. |
Tip
|
Если вы не используете фоновую задачу, но хотите изменять состояние UI-компонентов из не-UI потока, воспользуйтесь методами интерфейса |