簡體   English   中英

JavaFX任務結束和JavaFX線程化

[英]JavaFX Task ending and JavaFX threading

我今天才剛剛開始學習JavaFX,我試圖通過制作Snake克隆來了解更多有關JavaFX的信息,但是我在線程方面遇到了麻煩。 我想創建一個線程來更新蛇在屏幕上的位置,但是無法以正常的Runnable線程方式使用它,因為我正在該線程內使用JavaFX來更新繪制到屏幕上的矩形的位置(這是我了解到的您不能做,而必須使用Tasks,Services,Platform.runLater等?)我從中創建線程的類擴展了JavaFX.scene.layout.Pane,而我正在嘗試使用任務來更新蛇的位置。 我的問題是:該任務似乎只運行了一次或兩次並退出,而我沒有給出任何中斷。

擴展Pane的類的構造函數(Snake類擴展Group):

public GameFrame(){
    this.setPrefSize(800, 600);

    Snake snake = new Snake();
    this.getChildren().add(snake);

    taskThread = new Thread(new Task<Void>() { 
        protected Void call() throws Exception {
                while(!Thread.currentThread().isInterrupted()){
                    snake.updatePosition();
                    try{
                    Thread.sleep(1000);
                    } catch(InterruptedException e){
                        break;
                    }
                }
            return null;
        }
    });
    taskThread.start();
}

我覺得我實際上並不掌握在這里要做的最好的事情,而我試圖做的事情可能有些破舊。 關於我應該做什么或如何解決這個問題,有什么建議嗎?

JavaFX中線程化的基本規則(如果您已經了解其中的一些內容,請問完整,請原諒我):

  1. 任何阻止執行(或執行時間長)的操作都應在后台線程上運行-而不是在FX Application線程上運行
  2. 任何更改作為場景圖一部分的Node的狀態的操作都應在FX Application線程上執行

為了幫助實現這些目的,JavaFX API提供了一個Task類。 它具有一個返回值的call()方法; 它是一個Runnable因此可以作為Thread構造函數的參數提供,也可以傳遞給Executor 它還提供了保證在FX Application Thread上執行的有用回調,例如setOnSucceededsetOnFailed和各種update...()方法,這些屬性用於更新FX Application Thread上的progressmessage等屬性。

但是, Task類實際上是為一次性任務而設計的:例如,考慮需要從數據庫檢索數據的應用程序,這可能會花費一些時間。 它們執行特定的操作並返回結果。 您的情況有所不同,因為您的線程正在連續執行。

在這種情況下,最好使用簡單的Thread並使用Platform.runLater(...)更新UI。 Platform.runLater(...)接受一個Runnable並在FX Application Thread上執行其run()方法。

我不清楚您的代碼為什么會如此描述,但是假設方法調用snake.updatePosition()導致UI發生更改,應在FX Application Thread上執行。 無論如何我都會嘗試

taskThread = new Thread(new Runnable() { 
    public void run() {
            while(!Thread.currentThread().isInterrupted()){
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        snake.updatePosition();
                    }
                });
                try{
                    Thread.sleep(1000);
                } catch(InterruptedException e){
                    break;
                }
            }
    }
});

如果您使用的是Java 8,則用lambda替換匿名內部類會更好一些:

taskThread = new Thread( () -> {
    while (! Thread.currentThread().isInterrupted()) {
        Platform.runLater( snake::updatePosition );
        try {
            Thread.sleep(1000);
        } catch (InterruptedException exc) {
            break ;
        }
    }
});

JavaFX中用於定期執行某些操作的另一種技術是(ab?)使用Animation:

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
        new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                snake.updatePosition();
            }
        }
    ));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

或者,在Java 8中,略顯光滑

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
        event -> snake.updatePosition()));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM