将进度信息从Callable传播到Task [英] Propagate Progress Information from Callable to Task

查看:122
本文介绍了将进度信息从Callable传播到Task的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 javafx.concurrent.Task 在我们的JavaFX应用程序中执行后台工作。

I am using javafx.concurrent.Task to do background work in our JavaFX application.

当单位时测试这样的任务,我通常只是调用 task.call()。与 task.run()相反,这不会改变任务的状态(另请参阅 here 请投票取消删除)。如果我不调用任何更新..()方法,我可以调用 task.call()即使没有JavaFX平台正在运行。

When unit testing such tasks, I usually just invoke task.call(). In contrast to task.run(), this will not change the state of the task (see also here, please vote for undelete). If I do not call any update..() method, I can call task.call() even without the JavaFX Platform running.

我想重构这种方法独立于正在运行的JavaFX环境,并且移动执行 call()方法到JavaFX独立 Callable

I would like to refactor this approach to be independent from a running JavaFX environment, and move the implementation of the call() method into a JavaFX independent Callable.

测试这个独立的类会更简单,并且可以在任务中轻松使用这个可调用的。

Testing this independent class would be more simple and this callable can be easily used from within a task.

现在的问题是如何更新可调用的进度并将此进度信息传播到调用任务?

The question is now how can I update the callable's progress and propagate this progress information to the calling task?

任务通过受保护的更新...()方法进行更新,并且不使用专用对象(例如 org.eclipse.core.runtime .IProgressMonitor )这将使委托此功能变得容易。

Task does progress updating via protected update...() methods and does not use a dedicated object for that (e.g. like org.eclipse.core.runtime.IProgressMonitor) which would make delegating this functionality easy.

推荐答案

首先注意,当 javafx.concurrent package依赖于FX Toolkit运行,JavaFX Properties类没有这样的要求。因此,只要您只从单个线程访问JavaFX属性,在您想要使用的类中使用JavaFX属性就行是完全有效的,而无需运行FX Toolkit。

Note first that while the javafx.concurrent package relies on the FX Toolkit to be running, there is no such requirement on the JavaFX Properties classes. So, as long as you only access a JavaFX Property from a single thread, it would be perfectly valid to use JavaFX properties in classes that you wanted to use without requiring the FX Toolkit is running.

例如,您可以这样做:

public class MyProcess implements Callable<SomeData> {

    private final ReadOnlyDoubleWrapper progress = new ReadOnlyDoubleWrapper();

    public ReadOnlyDoubleProperty progressProperty() {
        return progress.getReadOnlyProperty() ;
    }

    public final double getProgress() {
        return progressProperty().get();
    }

    @Override
    public SomeData call() {
        final int numSteps = ... ;
        SomeData data = new SomeData();
        for (int i = 0 ; i < numSteps ; i++) {
            progress.set(1.0*i/numSteps);
            data.update(i);
        }
        return data ;
    }
}

这个类运行正常,不依赖于FX Toolkit正在运行。您可以将其包装在任务中,如下所示:

This class will run fine and doesn't depend on the FX Toolkit running. You can wrap it in a task as follows:

public class MyProcessTask extends Task<SomeData> {

    @Override
    protected SomeData call() throws Exception {
        MyProcess process = new MyProcess();
        process.progressProperty().addListener((obs, oldProgress, newProgress) ->
            updateProgress(newProgress, 1.0));
        return process.call();
    }
}

如果你想要 Callable 实现在API级别上独立于JavaFX(不仅仅是在不需要工具包运行的意义上),使用实现适当的回调非常容易。 java.util.function API。例如,你可以重构上面的内容

If you want you Callable implementation to be independent of JavaFX on an API level (not just in the sense of not requiring the toolkit to be running), it is pretty easy to implement the appropriate callbacks using the java.util.function API. For example, you could refactor the above as

public class MyProcess implements Callable<SomeData> {

    private DoubleConsumer progressUpdate = d -> {} ; // no-op
    private double progress ;

    public void setProgressUpdate(DoubleConsumer progressUpdate) {
        this.progressUpdate = progressUpdate ;
    }

    public final double getProgress() {
        return progress;
    }

    private void setProgress(double progress) {
        this.progress = progress ;
        progressUpdate.accept(progress);
    }

    @Override
    public SomeData call() {
        final int numSteps = ... ;
        SomeData data = new SomeData();
        for (int i = 0 ; i < numSteps ; i++) {
            setProgress(1.0*i/numSteps) ;
            data.update(i);
        }
        return data ;
    }
}

public class MyProcessTask extends Task<SomeData> {

    @Override
    protected SomeData call() throws Exception {
        MyProcess process = new MyProcess();
        process.setProgressUpdate(p -> updateProgress(p, 1.0));
        return process.call();
    }
}

这篇关于将进度信息从Callable传播到Task的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆