concurrency - Task chaining in JavaFX8: Start next Task after onSucceeded finished on previous task -
i'm rather new javafx8 , facing following problem in current app document processing/editing. have 2 rather expensive tasks, namely opening e document , saving document.
my app has buttons "import next", "export current" , "export current , import next". import , export, have 2 task of following structure:
private class export extends task<void> { public export() { this.setonrunning(event -> { // stuff (change cursor etc) }); this.setonfailed(event -> { // stuff, eg. show error box }); this.setonsucceeded(event -> { // stuff }); } @override protected void call() throws exception { // expensive stuff return null; } }
i submit task using executors.newsinglethreadexecutor();
.
for functionality "export current , import next", goal submit export , import tasks executor, import tasks should run if export-task sucessful , eventhandler given in "setonsucceedded" (whichs runs on gui thread) finished. if export fails, not make sense load next document because user interaction needed. how can achieved?
first tired entire logic/error handling in call-method, not work cannot change gui method (i.e. show error-box).
as workaround, i'm manually submitting import-task on last line of "setonsucceeded" in export-task, buts not flexible, because want sue task exports (without subsequent import)...
don't call handler property methods setonxxx
in task
subclass constructor. these set property on task, if call methods elsewhere replace functionality you're implementing in class itself, rather add it.
instead, override protected convenience methods:
public class export extends task<void> { @override protected void succeeded() { super.succeeded(); // stuff... } @override protected void running() { super.running(); // stuff... } @override protected void failed() { super.failed(); // stuff... } @override protected void call() { // expensive stuff.... return null ; } }
now can safely use setonxxx(...)
externally export
class without breaking functionality:
export export = new export(); export.setonsucceeded(e -> { import import = new import(); executor.submit(import); }); executor.submit(export);
this puts logic chaining tasks @ point create them, seem correct place it.
note way provide multiple handlers change of state register listeners stateproperty()
:
export export = new export(); export.stateproperty().addlistener((obs, oldstate, newstate) -> { if (newstate == worker.state.succeeded) { // ... } });
from testing, appears order of execution of these different mechanisms is:
- state listeners
- the
onsucceeded
handler - the
task.succeeded
method
all executed on fx application thread.
so if want code in task
subclass executed before handler added externally, do
public class export extends task<void> { public export() { stateproperty().addlistener((obs, oldstate, newstate) -> { if (newstate == worker.state.running) { // stuff } else if (newstate == worker.state.succeeded) { // stuff } else if (newstate == worker.state.failed) { // stuff } }); } @override public void call() { // ... } }
finally, implement entire logic in call
method: if need interact ui can wrap calls in platform.runlater(() -> {});
. however, separating functionality different tasks have done cleaner anyway.
Comments
Post a Comment