Platform.runLater і Task у JavaFX


88

Я робив кілька досліджень з цього приводу, але все ще дуже м'яко розгублений.

Хто-небудь може дати мені конкретний приклад того, коли використовувати Taskі коли використовувати Platform.runLater(Runnable);? У чому саме різниця? Чи існує золоте правило, коли слід використовувати будь-яке з них?

Також виправте мене, якщо я помиляюся, але хіба ці два "Об'єкти" не є способом створення чергового потоку всередині основного потоку в графічному інтерфейсі (використовується для оновлення графічного інтерфейсу)?

Відповіді:


108

Використовуйте Platform.runLater(...)для швидких і простих операцій, а також Taskдля складних і великих операцій.

Приклад: Чому ми не можемо використовувати Platform.runLater(...)для довгих обчислень (взято з посилання нижче).

Проблема: фоновий потік, який нараховує лише від 0 до 1 мільйона, і рядок прогресу оновлення в інтерфейсі користувача.

Використання коду Platform.runLater(...):

final ProgressBar bar = new ProgressBar();
new Thread(new Runnable() {
    @Override public void run() {
    for (int i = 1; i <= 1000000; i++) {
        final int counter = i;
        Platform.runLater(new Runnable() {
            @Override public void run() {
                bar.setProgress(counter / 1000000.0);
            }
        });
    }
}).start();

Це огидна частина коду, злочин проти природи (та програмування загалом). По-перше, ви втратите клітини мозку, просто дивлячись на це подвійне вкладання Runnables. По-друге, це збирається заповнити чергу подій маленькими Runnables - насправді їх мільйон. Очевидно, що нам потрібен якийсь API, щоб полегшити написання фонових працівників, які потім обмінюються даними з інтерфейсом.

Код за допомогою Завдання:

Task task = new Task<Void>() {
    @Override public Void call() {
        static final int max = 1000000;
        for (int i = 1; i <= max; i++) {
            updateProgress(i, max);
        }
        return null;
    }
};

ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
new Thread(task).start();

воно не страждає від жодної вади, виявленої в попередньому кодексі

Довідково: Worker Threading у JavaFX 2.0


Приклад завдання у додатку Ensemble більше не працюватиме.
Кугомастік

Це правильне посилання, але я не можу його редагувати, оскільки редагування складає лише 2 символи.
Aerus

29
Сказати, що один для "швидких" операцій, а інший для "складних", трохи вводить в оману. Зрештою, головна відмінність полягає в тому, що один дозволяє запускати код у графічному інтерфейсі JFX звідкись ще, а інший робить прямо протилежне - дозволяє запускати код у фоновому потоці з потоку графічного інтерфейсу (додаючи бонус здатний взаємодіяти з потоком графічного інтерфейсу в процесі).
Сергій Таченов

Я хочу зберегти зображення кожної зі сцен - і це займе час. Чи це спричинить проблеми при запуску в окремому потоці через Task? Я зрозумів, що вся робота, пов’язана з графічним інтерфейсом, повинна відбуватися в потоці FxApplication.
StephenBoesch

@ Сергій-Таченов Отже, ви використовуєте runLater () із потоку Завдання для оновлення потоку графічного інтерфейсу у випадках, коли ви хочете зробити більше, ніж просто оновити одну властивість, як прогрес?
simpleuser

58
  • Platform.runLater: Якщо вам потрібно оновити компонент графічного інтерфейсу з потоку, що не є графічним інтерфейсом, ви можете використати його, щоб помістити своє оновлення в чергу, і воно буде оброблено потоком графічного інтерфейсу якомога швидше.
  • Taskреалізує Workerінтерфейс, який використовується, коли вам потрібно запустити довге завдання поза потоком графічного інтерфейсу (щоб уникнути заморожування програми), але все одно потрібно взаємодіяти з графічним інтерфейсом на якомусь етапі.

Якщо ви знайомі з Swing, перший є еквівалентом, SwingUtilities.invokeLaterа другий - поняттям SwingWorker.

Javadoc завдання дає багато прикладів , які повинні прояснити , як вони можуть бути використані. Ви також можете звернутися до підручника з паралельності .


Дякую. Чи можете ви навести невеликий приклад використання платформи? Чи можете ви використовувати його поза потоком gui чи? І приклади завдань у документах насправді незрозумілі
Марк Расмуссен,

Так Platform.runLater можна використовувати поза потоком графічного інтерфейсу - це його основне призначення. Можливо, цей посібник із завдань буде більш інформативним, ніж javadoc.
assylias

3
Ви використовуєте Platform.runLater Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
пізніше так

як я зможу використовувати компоненти графічного інтерфейсу тоді =: S
Марк Расмуссен

1
@KevinMeredith Метод виклику Завдання не слід викликати в потоці FX - але Task надає мостові методи (updateProgress тощо), які працюють у потоці FX. Докладнішу інформацію див. У навчальних посібниках для Java.
assylias

12

Тепер його можна змінити на лямбда-версію

@Override
public void actionPerformed(ActionEvent e) {
    Platform.runLater(() -> {
        try {
            //an event with a button maybe
            System.out.println("button is clicked");
        } catch (IOException | COSVisitorException ex) {
            Exceptions.printStackTrace(ex);
        }
    });
}

8
Якщо ви обробляєте подію графічного інтерфейсу, ви знаходитесь у потоці графічного інтерфейсу. Чому б ви тоді використовували runLater ()?
TFuto

Хоча ви маєте рацію, відповідь Каглара намагався висвітлити використання лямбда-виразу, не обов'язково даючи хороший приклад кодування. Я використовуюPlatform.runLater(() -> progressBar.setProgress(X/Y));
Таельсін

2

Однією з причин використання явного Platform.runLater () може бути те, що ви прив’язали властивість в інтерфейсі до властивості служби (результату). Отже, якщо ви оновлюєте властивість пов'язаного сервісу, ви повинні зробити це за допомогою runLater ():

У потоці інтерфейсу користувача, також відомому як потік JavaFX Application:

...    
listView.itemsProperty().bind(myListService.resultProperty());
...

у реалізації Служби (фоновий працівник):

...
Platform.runLater(() -> result.add("Element " + finalI));
...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.