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:

  1. state listeners
  2. the onsucceeded handler
  3. 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

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -