使用2个按钮启动和停止JavaFX后台线程

时间:2018-04-06 04:35:34

标签: java multithreading javafx-8

我正在尝试创建一个简单的UI来启动selenium测试,该测试能够启动后台线程,当按下“开始”按钮时启动浏览器并停止线程并在按下“停止”按钮时将其关闭。 不幸的是,当我在启动后单击停止时,它不起作用。如果我让它完成我无法重启线程。我将如何进行更新,以便我可以提交一个可以通过停止按钮停止的新线程。

DatabaseReference mFirebaseDatabaseReference = FirebaseDatabase.getInstance().getReference();
Query query = mFirebaseDatabaseReference.child("users").orderByChild("name").equalTo("Fazal");
query.addValueEventListener(valueEventListener);

ValueEventListener valueEventListener = new ValueEventListener()
{
    @Override
    public void onDataChange(DataSnapshot dataSnapshot)
    {
        for (DataSnapshot postSnapshot : dataSnapshot.getChildren())
        {
            //TODO get the data here
            User user = dataSnapshot.getValue(User.class);

        }

    }

    @Override
    public void onCancelled(DatabaseError databaseError)
    {

    }
};

1 个答案:

答案 0 :(得分:1)

根据documentation

  

与FutureTask一样,Task是一次性类,无法重用。请参阅服务以获取可重复使用的工作人员。

所以你必须为每次运行创建新任务。所以我在Main中添加了task作为字段:

Stage window;
GridPane grid;
Task<Void> task;

然后在单击开始按钮时创建任务:

buttonStart.setOnAction(new EventHandler<ActionEvent>() {
    /*
     * Start Button Clicked
     */
    @Override
    public void handle(ActionEvent event) {
        if(task != null) {
            System.out.println("Task already running");
            return;
        }
        task = new Task<Void>() {
            @Override
            protected Void call() {
                new VisitPage().start(this, URLTextField.getText());
                ;
                return null;
            }
        };
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }
});

点击停止按钮,你必须取消任务:

buttonStop.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            if(task == null) {
                System.out.println("Task not running");
                return;
            }
            System.out.println("Stop Pressed");
            task.cancel();
            task = null;
        }
    });

这不会做任何事情,因为你有责任在取消任务时结束任务,并且你没有结束你的无限循环。 所以你的VisitPage应该是这样的(我跳过了测试细节,因为我没有在classpath上使用它们):

public class VisitPage {
    public void start(Task<Void> task, String URL) {
        while (!task.isCancelled()) {
            System.out.println("Running test");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("Test run ended");
        }
        System.out.println("Canceling...");
        System.out.println("Stop Pressed");
        return;
    }
}

一些小问题:

技术上task.cancel()有时会结束你的线程,如果你的线程处于休眠状态时你不会捕获被抛出的InterruptedException

我不确定你的代码是如何编译的,但我必须将一些变量最终化,以便它们可以在处理程序中使用:(没关系,从Java SE 8局部变量可以有效地最终)

final TextField URLTextField = new TextField();
//...
final  Task<Void> task = new Task<Void>(){
//...

我会将创建的线程定义为守护进程,以便在不停止测试的情况下关闭UI时它不会继续运行:

Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();

我还将Start方法重命名为start