繁体   English   中英

Platform.runLater() 如何发挥作用?

[英]How does Platform.runLater() function?

我有一个简单的应用程序,它在后台更新数据,当它更新时,它会禁用所有其他按钮并启用 TextArea 来显示进度。

脚步:

  1. 禁用 mainUI 中的所有其他按钮(按钮名称:plotButton)

  2. 启用显示更新已开始的 TextArea(TextArea 名称:infoLogTextArea)

  3. 然后只启动更新方法(update() 抛出异常)。

这是代码:

@FXML
    public void handleUpdateButton() {
        
        infoLogTextArea.setVisible(true);
        infoLogTextArea.appendText("Please wait while downloading data from internet.....\n");      
        plotButton.setDisable(true);
        updateButton.setDisable(true);
            
        if(c!=null) {
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    // Thread.sleep(10000); -> sleep for 10secs
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                c.updateData();
                                infoLogTextArea.appendText(c.getErrorLog().toString());
                                plotLabel.setText(c.getCityData().size()+" cities found and updated from internet");
                                infoLogTextArea.appendText("Successfully updated the data from Internet\n");
                            }catch (IOException e) {
                                infoLogTextArea.setText("Couldnot update the data from web: "+e.getMessage()+"\n");
                            }
                            finally {
                                plotButton.setDisable(false);
                                updateButton.setDisable(false);
                            }
                        }
                    });
                }
            };
            
            new Thread(task).start();
            
        }else {
            System.out.println("c not initialized");
        }
    }

现在代码运行良好,但有时第 1 步和第 2 步没有执行,它开始第 3 步(更新),这会冻结程序。 如果我将 Thread.sleep(10 secs) 放在第 2 步和第 3 步之间,则它完全正常 (它在代码中注释)

但是有人能解释一下幕后发生了什么以及为什么Platform.runLater()不能一直工作吗?

JavaFX 应用程序在应用程序线程上运行,该线程处理所有 UI 元素。 这意味着如果您单击按钮 A 并单击该按钮启动需要 5 秒才能完成的方法 A,然后单击该按钮一秒钟后,您尝试单击启动方法 B 的按钮 B,方法 B 将不会启动,直到方法一个结束。 或者按钮 B 可能在方法 A 完成之前甚至无法工作,我对那里的细节有点模糊。

阻止应用程序冻结的一个好方法是使用线程。 要解决上述情况,单击按钮 A 将启动启动新线程的方法 A。 然后线程可以在不锁定 UI 并阻止您单击按钮 B 的情况下完成它想要完成的时间。

现在,说一些需要在应用程序线程上的方法 A 中的内容,例如,它更新了一个 UI 组件,如标签或文本字段。 然后在方法 A 的线程中,您需要将影响 UI 的部分放入Platform.runLater() ,以便它与 UI 的其余部分一起在应用程序线程上运行。

对于您的示例,这意味着您有两个选择。
1. 根本不要使用线程,因为您不希望用户在更新发生时与 UI 交互。
2. 像这样将c.updateData()移出Platform.runLater()

 Runnable task = new Runnable() {
            @Override
            public void run() {
                c.updateData();
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            infoLogTextArea.appendText(c.getErrorLog().toString());
                            plotLabel.setText(c.getCityData().size()+" cities found and updated from internet");
                            infoLogTextArea.appendText("Successfully updated the data from Internet\n");
                        }catch (IOException e) {
                            infoLogTextArea.setText("Couldnot update the data from web: "+e.getMessage()+"\n");
                        }
                        finally {
                            plotButton.setDisable(false);
                            updateButton.setDisable(false);
                        }
                    }
                });
            }
        };

其中任何一个都可以工作,但您现在所做的是在应用程序线程上,然后启动另一个线程,其唯一目的是在应用程序线程上运行某些内容。

Platform 类的文档很好地解释了一切:

public static void runLater(Runnable runnable)

在将来某个未指定的时间JavaFX 应用程序线程上运行指定的 Runnable。 这个方法可以从任何线程调用,它将 Runnable 发布到一个事件队列,然后立即返回给调用者。 Runnables 按照它们发布的顺序执行。 传入 runLater 方法的 runnable 将在任何传入 runLater 的 Runnable 之前执行。 如果在 JavaFX 运行时关闭后调用此方法,则该调用将被忽略:不会执行 Runnable 并且不会抛出异常。 注意:应用程序应该避免用太多挂起的 Runnables 淹没 JavaFX。 否则,应用程序可能会变得无响应 鼓励应用程序将多个操作批处理为更少的 runLater 调用。 此外,长时间运行的操作应尽可能在后台线程上完成,从而释放 JavaFX 应用程序线程用于 GUI 操作。

在初始化 FX 运行时之前不得调用此方法。 对于扩展 Application 并使用 Java 启动器或 Application 类中的启动方法之一来启动应用程序的标准 JavaFX 应用程序,FX 运行时由启动器在加载 Application 类之前初始化。

因此,使用 runLater 仅更新非 JavaFX 线程上的任何 UI 元素,并将任何繁重的工作留给后台线程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM