将进度信息从Callable传播到Task [英] Propagate Progress Information from Callable to 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屋!