JavaFX의 Platform.runLater 및 Task


88

나는 이것에 대해 약간의 연구를 해왔지만 여전히 가장 적게 말하는 것은 매우 혼란 스럽습니다.

누구든지 언제 사용 Task하고 언제 사용 Platform.runLater(Runnable);하는지에 대한 구체적인 예를 줄 수 있습니까 ? 차이점은 정확히 무엇입니까? 이들 중 언제 사용 하는가에 대한 황금률이 ​​있습니까?

또한 내가 틀렸지 만이 두 "객체"가 GUI의 주 스레드 내부에 다른 스레드를 만드는 방법이 아닌 경우에도 수정하십시오 (GUI 업데이트에 사용됨)?

답변:


108

사용하여 Platform.runLater(...)빠르고 간단하게 작업하고 Task복잡하고 큰 작업.

예 : Platform.runLater(...)긴 계산에 사용할 수없는 이유 (아래 참조에서 발췌).

문제 : 0에서 1 백만까지 계산되는 백그라운드 스레드와 UI의 업데이트 진행률 표시 줄.

다음을 사용하는 코드 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로 이벤트 대기열을 휩쓸 것입니다. 실제로는 백만 개입니다. 분명히, 우리는 UI와 다시 통신하는 백그라운드 워커를 더 쉽게 작성하기 위해 약간의 API가 필요했습니다.

Task를 사용하는 코드 :

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();

이전 코드에 나타난 결함이 없습니다.

참조 : JavaFX 2.0의 작업자 스레딩


Ensemble 앱 링크의 작업 예제가 더 이상 작동하지 않습니다.
Cugomastik 2014-08-05

이것은 올바른 링크 이지만 편집이 2 자 밖에 없기 때문에 편집 할 수 없습니다.
Aerus

29
하나는 "빠른"작업을위한 것이고 다른 하나는 "복잡한"작업을위한 것이라고 말하는 것은 약간 오해의 소지가 있습니다. 결국 가장 큰 차이점은 하나는 다른 곳에서 JFX GUI 스레드에서 코드를 실행할 수 있고 다른 하나는 정확히 반대입니다. GUI 스레드에서 백그라운드 스레드에서 코드를 실행할 수 있습니다 (존재하는 보너스 추가 프로세스에서 GUI 스레드와 통신 할 수 있음).
Sergei Tachenov

각 장면의 이미지를 저장하고 싶습니다. 시간이 걸립니다. 태스크를 통해 별도의 스레드에서 실행할 때 문제가 발생합니까? 모든 GUI 관련 작업은 FxApplication 스레드에서 발생해야한다는 것을 이해했습니다.
StephenBoesch 2015-08-09

@ Sergey-Tachenov 그래서 진행과 같은 단일 속성을 업데이트하는 것 이상을 수행하려는 경우 GUI 스레드를 업데이트하기 위해 태스크 스레드에서 runLater ()를 사용합니까?
simpleuser

58
  • Platform.runLater: GUI가 아닌 스레드에서 GUI 구성 요소를 업데이트해야하는 경우이를 사용하여 업데이트를 대기열에 넣을 수 있으며 가능한 한 빨리 GUI 스레드에서 처리합니다.
  • TaskWorkerGUI 스레드 외부에서 긴 작업을 실행해야하지만 (애플리케이션 동결을 방지하기 위해) 일부 단계에서 여전히 GUI와 상호 작용해야 할 때 사용되는 인터페이스를 구현합니다 .

Swing에 대해 잘 알고 있다면 전자는 SwingUtilities.invokeLater의 개념과 같고 후자는의 개념과 같습니다 SwingWorker.

Taskjavadoc은 사용 방법을 명확히해야하는 많은 예제를 제공합니다. 동시성대한 자습서를 참조 할 수도 있습니다 .


감사합니다 플랫폼 사용 방법에 대한 간단한 예를 들어 주실 수 있습니까? GUI 스레드 외부에서 사용할 수 있습니까? 그리고 문서의 작업 예제는 정말 불분명합니다
Marc Rasmussen

예 Platform.runLater는 GUI 스레드 외부에서 사용할 수 있습니다. 이것이 주요 목적입니다. 이 튜토리얼 은 javadoc보다 더 많은 정보를 얻을 수 있습니다 .
assylias

3
다음과 같이 Platform.runLater를 사용합니다.Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
assylias

GUI 구성 요소를 어떻게 사용할 수
Marc Rasmussen

1
@KevinMeredith Task의 호출 메서드는 FX 스레드에서 호출되지 않아야합니다. 그러나 Task는 FX 스레드에서 실행되는 브리지 메서드 (updateProgress 등)를 제공합니다. 자세한 내용은 javadoc 및 자습서를 참조하십시오.
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
GUI 이벤트를 처리하는 경우 GUI 스레드에 있습니다. 그렇다면 왜 runLater ()를 사용합니까?
TFuto

당신이 옳았지만 Caglar의 대답은 좋은 코딩 예제를 제공하기 위해 반드시 람다 식의 사용을 강조하려는 것이 었습니다. 나는 사용Platform.runLater(() -> progressBar.setProgress(X/Y));
Taelsin 16.11.

2

명시 적 Platform.runLater ()를 사용하는 한 가지 이유는 UI의 속성을 서비스 (결과) 속성에 바인딩했기 때문일 수 있습니다. 따라서 바인딩 된 서비스 속성을 업데이트하는 경우 runLater ()를 통해이를 수행해야합니다.

JavaFX 애플리케이션 스레드라고도하는 UI 스레드에서 :

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

서비스 구현 (백그라운드 작업자) :

...
Platform.runLater(() -> result.add("Element " + finalI));
...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.