当我运行另一个线程时,JavaFx进度指示器冻结

时间:2014-03-08 20:21:26

标签: java multithreading javafx-2

所以我一直试图实现一个没有运气的进度指标。尽管我已经阅读了一些关于Platform.RunLater和Tasks的内容,但我不太清楚我是否理解使用JavaFx管理线程。所以这是我的用例。

我的程序允许用户连接到数据库并查看数据库中的一些模式和其他对象。有时连接到大型数据库并提取其所有表和信息需要一段时间,所以我想显示一个进度指示器。我并不是试图更新进度,我只是想让进度指示器在值-1时可见,同时进程正在运行以从数据库中提取所有内容。理想情况下,我将从FXML文件中加载一个不可见的进度指示器。当我开始从数据库中提取信息的过程时,我想让它可见。

当试图使我的进度可见时,它从未出现,所以我决定开始让它可见并使其不可见,只是为了看看会发生什么。当我打开程序时,进度指示器旋转得很好,但是一旦我尝试连接到数据库,它就会停止旋转并冻结。我认为这是当我试图让它可见时发生的事情,这就是为什么它永远不会出现。

以下是我目前的代码,我将非常感谢任何有关解释的详细帮助,以便我能够理解正在发生的事情。感谢

来自正在完成大部分工作的方法。

                //make progress indicator visible
                pi.setVisible(true);

                // separate non-FX thread
                ExtractorThread t = new ExtractorThread();
                t.setCp(cp);
                t.start();

                //Wait until the thread is done
                try{
                    t.join();
                }
                catch(Exception e){
                    e.printStackTrace();
                }

                //Retrieve the dbextractor from the thread
                DbExtractor dbe = t.getDbe();
                //move on to the next page in the application
                this.caster.goToDataSource(c, cp, dbe);

执行工作的ExtractorThread。

private class ExtractorThread extends Thread{
    private ConnectionProperties cp;
    private DbExtractor dbe;

    public void run() {
        dbe = new DbExtractor(cp);
        try {
            dbe.extract();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   

    }

    public DbExtractor getDbe() {
        return dbe;
    }

    public void setCp(ConnectionProperties cp) {
        this.cp = cp;
    }
}

如果我应该使用Platform.RunLater,我不知道在哪里使用它或为什么。任何帮助将不胜感激,谢谢!

2 个答案:

答案 0 :(得分:2)

使用javafx.concurrent API。扩展任务而不是线程:

private class ExtractorThread extends Task<DbExtractor>{
    private ConnectionProperties cp;

    public DbExtractor call() throws Exception {
        dbe = new DbExtractor(cp);
        dbe.extract();
        return dbe;   

    }


    public void setCp(ConnectionProperties cp) {
        this.cp = cp;
    }
}

然后做:

        //make progress indicator visible
        pi.setVisible(true);

        // separate non-FX thread
        final ExtractorThread t = new ExtractorThread();
        t.setCp(cp);
        t.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            public void handle(WorkerStateEvent event) {
               DbExtractor dbExtractor = t.getValue();
               this.caster.goToDataSource(c, cp, dbe);
            }
        });
        t.setOnFailed(...); // similarly, to handle exceptions
        new Thread(t).start();

答案 1 :(得分:1)

我不编码JavaFX,所以我不能给你章节和经文,但这一行:

t.join();

将阻止调用代码,直到后台线程通过。不要这样做。而是使用某种类型的侦听器在后台线程完成时得到通知。如果这是Swing,我会使用添加到SwingWorker的PropertyChangeListener在后台线程完成时通知我。我认为你仍然可以使用PropertyChangeListener与JavaFX做类似的事情,但我不能告诉你这是否代表规范的解决方案。

另外,不要扩展Thread,而是实现Runnable。这不会解决您的问题,但是基本的Java常识。