수색…


Platform.runLater를 사용하여 UI 업데이트

장기 실행 작업은 JavaFX 응용 프로그램 스레드에서 실행하면 안됩니다. 이로 인해 JavaFX가 UI를 업데이트하지 못하게되어 UI가 고정됩니다.

또한 "라이브"장면 그래프의 일부인 Node 변경 사항은 JavaFX 응용 프로그램 스레드에서 발생 해야합니다 . Platform.runLater 를 사용하여 JavaFX 응용 프로그램 스레드에서 해당 업데이트를 실행할 수 있습니다.

다음 예제는 다른 스레드에서 Text Node 반복적으로 업데이트하는 방법을 보여줍니다.

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class CounterApp extends Application {

    private int count = 0;
    private final Text text = new Text(Integer.toString(count));

    private void incrementCount() {
        count++;
        text.setText(Integer.toString(count));
    }

    @Override
    public void start(Stage primaryStage) {
        StackPane root = new StackPane();
        root.getChildren().add(text);

        Scene scene = new Scene(root, 200, 200);

        // longrunning operation runs on different thread
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                Runnable updater = new Runnable() {

                    @Override
                    public void run() {
                        incrementCount();
                    }
                };

                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                    }

                    // UI update is run on the Application thread
                    Platform.runLater(updater);
                }
            }

        });
        // don't let thread prevent JVM shutdown
        thread.setDaemon(true);
        thread.start();

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

UI 업데이트 그룹화

다음 코드는 너무 많은 Platform.runLater 호출이 사용되므로 버튼을 누른 후 잠시 동안 UI가 응답하지 않게합니다. (단추를 클릭 한 직후에 ListView 스크롤 해보십시오.)

@Override
public void start(Stage primaryStage) {
    ObservableList<Integer> data = FXCollections.observableArrayList();
    ListView<Integer> listView = new ListView<>(data);
    
    Button btn = new Button("Say 'Hello World'");
    btn.setOnAction((ActionEvent event) -> {
        new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                final int index = i;
                Platform.runLater(() -> data.add(index));
            }
        }).start();
    });

    Scene scene = new Scene(new VBox(listView, btn));

    primaryStage.setScene(scene);
    primaryStage.show();
}

많은 수의 업데이트를 사용하지 않고이를 방지하기 위해 다음 코드에서는 AnimationTimer 를 사용하여 프레임 당 한 번만 업데이트를 실행합니다.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.AnimationTimer;

public class Updater {

    @FunctionalInterface
    public static interface UpdateTask {

        public void update() throws Exception;
    }

    private final List<UpdateTask> updates = new ArrayList<>();

    private final AnimationTimer timer = new AnimationTimer() {

        @Override
        public void handle(long now) {
            synchronized (updates) {
                for (UpdateTask r : updates) {
                    try {
                        r.update();
                    } catch (Exception ex) {
                        Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                updates.clear();
                stop();
            }
        }
    };

    public void addTask(UpdateTask... tasks) {
        synchronized (updates) {
            updates.addAll(Arrays.asList(tasks));
            timer.start();
        }
    }

}

Updater 클래스를 사용하여 업데이트를 그룹화 할 수 있습니다.

private final Updater updater = new Updater();

...

        // Platform.runLater(() -> data.add(index));
        updater.addTask(() -> data.add(index));

JavaFX 서비스 이용 방법

JavaFX Thread 로 집중적 인 작업을 실행하는 대신 Service 로 수행해야합니다. 기본적으로 서비스 는 무엇입니까?

서비스는 시작될 때마다 새로운 Thread 생성하고 작업 을 전달하여 작업 을 수행하는 클래스입니다. 서비스는 값을 반환하거나 반환 할 수 없습니다.

다음은 JavaFX Service의 전형적인 예입니다.이 작업은 Map<String,String>( )을 반환합니다.

public class WorkerService extends Service<Map<String, String>> {

    /**
     * Constructor
     */
    public WorkerService () {

        // if succeeded
        setOnSucceeded(s -> {
            //code if Service succeeds
        });

        // if failed
        setOnFailed(fail -> {
            //code it Service fails
        });

        //if cancelled
        setOnCancelled(cancelled->{
            //code if Service get's cancelled
        });
    }

    /**
    * This method starts the Service
    */
    public void startTheService(){
        if(!isRunning()){
           //...
           reset();
           start();
        }

    }

    @Override
    protected Task<Map<String, String>> createTask() {
        return new Task<Map<String, String>>() {
            @Override
            protected Void call() throws Exception {

                    //create a Map<String, String>
                    Map<String,String> map  = new HashMap<>();

                   //create other variables here

                   try{
                        //some code here
                        //.....do your manipulation here

                        updateProgress(++currentProgress, totalProgress);
                    }

                } catch (Exception ex) {                  
                    return null; //something bad happened so you have to do something instead of returning null
                }

                return map;
            }
        };
    }

}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow