如何在Task中设置Var?

时间:2013-11-03 17:06:26

标签: java multithreading javafx-2 javafx task

首先,我是JavaFX的新手,很抱歉,如果这个问题很愚蠢。如何从任务中获取返回对象?

继承我的问题:

我想从模拟中获取一个对象列表。模拟的延迟时间为1到5秒。但我不想要,我的GUI在这个时候冻结了。

在Java.Swing中,使用Thread很容易,但就我所知,JavaFX具有Tasks。

我已经阅读了很多教程,但是在任何地方都会返回文本属性。所以这是我的问题:如何使用任务/线程(在我的情况下为列表)中计算结果来设置Object的值

谢谢。

2 个答案:

答案 0 :(得分:2)

你是对的,因为这些例子似乎掩盖了从任务中获取结果。您可以通过两种方式获取我所知道的结果:

  1. 通过Task类的getValue()方法(这是我完成它的方式)
  2. 通过父FutureTask类的get()方法(我没有使用过它,但原则上它应该可以工作)。
  3. 使用第一个getValue()方法,您需要确保该任务通过任务的调用方法中的updateValue(...)方法设置值。然后在WorkerStateEvent

    上放置一个监听器
    myTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
    
        @SuppressWarnings("unchecked")
        @Override
        public void handle(WorkerStateEvent event) {
            ReturnType rt =  (ReturnType) event.getSource().getValue()
            // ... other stuff to do here ...
        }
    });
    

    第一种方法有点冗长,但它可以工作,并允许在任务完成后进行一些更复杂的操作。

    第二种方法稍微简单明了,但在任务完成时并没有给你多少控制。使用FutureTask的get()方法,代码应该阻塞,直到Task返回值。所以使用它应该简单:

    //
    // Start the task in a thread (using whatever approach you like) 
    //before calling the get() method.
    //
    ReturnType rt = myTask.get();
    

    我已将Future个对象与其他代码一起使用,但我没有将FutureTask与FX api一起使用,所以我无法告诉你是否有隐藏的陷阱。

    祝你好运,

    chooks

答案 1 :(得分:2)

任务是一种通用类型。这意味着如果将类型应用于像Task<Integer>这样的任务,则Task类将具有返回Integer的函数。其中一个函数是valueProperty(),它可以绑定到其他场景元素。以标签显示,或其他任何东西。我建议你阅读the javafx binding tutorial,以便更好地理解。

以下是使用任务或其属性的示例。

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TestingTasks extends Application{

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

    @Override
    public void start(Stage stage) throws Exception {

        VBox vbox = new VBox(10);
        vbox.setAlignment(Pos.TOP_CENTER);

        ListView<String> list = new ListView<>();
        HBox hbox = new HBox(10);
        hbox.setAlignment(Pos.CENTER_LEFT);
        Label labelMessage = new Label();
        hbox.getChildren().addAll(new Label("Message: "), labelMessage);
        ProgressBar progress = new ProgressBar(-1);
        progress.setVisible(false);

        Button button = new Button("Executing Task");
        button.setOnAction(event(button, list, progress, labelMessage));

        vbox.getChildren().addAll(list, hbox, button, progress);
        Scene scene = new Scene(vbox, 400, 300);
        stage.setScene(scene);
        stage.show();
    }

    private EventHandler<ActionEvent> event(final Button button, final ListView<String> list, final ProgressBar progress, final Label labelMessage) {       
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Task<ObservableList<String>> task = generateTask();
                list.itemsProperty().bind(task.valueProperty());
                progress.visibleProperty().bind(task.runningProperty());
                labelMessage.textProperty().bind(task.messageProperty());
                button.disableProperty().bind(task.runningProperty());
                task.runningProperty().addListener(listenerRunningTask());
                Thread t = new Thread(task);
                t.setDaemon(true);
                t.start();
            }

        };
    }

    private Task<ObservableList<String>> generateTask() {               
        return new Task<ObservableList<String>>() {                 
            @Override
            protected ObservableList<String> call() throws Exception {
                updateMessage("Waiting...");
                Thread.sleep(5000);
                updateMessage("Waking up");
                return FXCollections.observableArrayList("One", "Two", "Three");
            }
        };
    }   

    private ChangeListener<? super Boolean> listenerRunningTask() {     
        return new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if(oldValue && !newValue){
                    //TODO when finish
                }               
            }
        };
    }   
}

基本上,你可以在Task中返回一个变量,或者等待Task结束并执行一些东西,创建你自己的绑定......

如果你想从线程中修改屏幕的某些内容,你需要从FX线程中执行它,任务函数调用在FX线程之外,因此屏幕不会冻结。但是所有绑定元素都将出现在FX线程中,因此可以安全地修改GUI。

如果要从非FX线程安全地修改GUI,只需执行:

Platform.runLater(new Runnable() {                  
    @Override
    public void run() {
        //Safe modification in the FX Thread
    }
});

另请查看concurrency in JavaFX2。这更深入地解释了并发性,服务,任务......

希望它有所帮助!