我有一个并发任务,可以处于两种状态 - 活动(工作)和暂停(通过
Thread.sleep(xxxx)
)。当任务不确定地工作时,ProgressIndicator
应该可见,以向用户显示正在运行的Task
。当任务暂停时,不应显示 ProgressIndicator
。
这是我的解决方案:
public class JavaFxTest7 extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
var indicator = new ProgressIndicator();
indicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
var vBox = new VBox(indicator);
var scene = new Scene(vBox, 300, 200);
stage.setScene(scene);
stage.show();
Task<Boolean> task = new Task<Boolean>() {
@Override
protected Boolean call() throws Exception {
while(!isCancelled()) {
this.updateValue(true);
for (long l = 1; l < 150000L; l++) {
System.out.println("Working");
}
System.out.println("Pause");
this.updateValue(false);
Thread.sleep(2500);
}
return null;
}
};
indicator.visibleProperty().bind(task.valueProperty());
new Thread(task).start();
}
}
这段代码按预期工作,并完成了我需要的一切。但是,我不喜欢这个解决方案,因为它不合逻辑。我使用任务值来控制指标的可见性,但效果不好。我想将侦听器添加到
Task
状态属性,但据我所知,我无法控制状态。
对于这样的问题有更好的解决方案吗?也许我应该使用
Service
而不是 Task
?
不幸的是,您将无法通过
state
属性来执行此操作。 Task
API 不提供设置该属性的方法。尽管即使您可以设置它,但没有一个枚举常量似乎能够正确传达“暂停”的概念。
为了避免通过
value
属性实现此目的,您可以创建自己的 Task
子类,它公开一个新的“暂停”布尔属性。然后,您只需确保仅更新 JavaFX 应用程序线程 上的该属性。下面是一个示例,其中对属性的更新以与 Task
合并对 title
、message
、progress
和 value
的更新的方式合并。
import java.util.concurrent.atomic.AtomicReference;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.concurrent.Task;
public abstract class PauseableTask<T> extends Task<T> {
private final ReadOnlyBooleanWrapper paused = new ReadOnlyBooleanWrapper(this, "paused");
private void setPaused(boolean paused) { this.paused.set(paused); }
public final boolean isPaused() { return paused.get(); }
public final ReadOnlyBooleanProperty pausedProperty() {
return paused.getReadOnlyProperty();
}
private final AtomicReference<Boolean> pausedConflater = new AtomicReference<>();
protected final void updatePaused(boolean paused) {
if (Platform.isFxApplicationThread()) {
setPaused(paused);
} else if (pausedConflater.getAndSet(paused) == null) {
Platform.runLater(() -> setPaused(pausedConflater.getAndSet(null)));
}
}
}