java - JavaFX. Where to put service class reference? Controller or Main app starter class? -


i work javafx application , use fxml implement mvc pattern. make proof of concept, , start create javafx user interface.

in previous experience spring mvc, there usual create service , inject them in controller class via annotations. javafx cannot find recommendations how that. not sure have put services controller, or call main class method controller. second solution holds service reference in main application class.

please note application runs service classes in concurrent threads. of them implements runnable interface

i avoid having controllers needing refer main application class introduces dependency not necessary. have each controller keep reference service object.

to provide service controllers, can use 1 of techniques outlined in this question.

there 3 ways this:

creating controller , setting in fxmlloader directly

in version, do not use fx:controller attribute in root element of fxml file (doing cause exception thrown).

given

public interface service { ... } 

and

public class somecontroller {      private final service service ;      public somecontroller(service service) {         this.service = service ;     }      // ... } 

then can load fxml file

service service = ... ; fxmlloader loader = new fxmlloader(getclass().getresource("path/to/fxml/file.fxml")); somecontroller controller = new somecontroller(service.class); loader.setcontroller(controller); parent uiroot = loader.load(); 

retrieving controller fxmlloader , setting service

if want able use fx:controller attribute, controller class must have no-argument constructor. in case, can set service on controller after fxmlloader has completed loading. looks like:

public class somecontroller {      private service service ;      public void initservice(service service) {         this.service = service ;         // update ui values service...     }      // ... } 

note here have refactor code initialize() method, code may depend on service, not have been set when initialize() invoked. move such code initservice(...) method. loading fxml file looks like

service service = ... ; fxmlloader loader = new fxmlloader(getclass().getresource("path/to/fxml/file.fxml")); parent uiroot = loader.load(); somecontroller controller = loader.getcontroller(); controller.initservice(service); 

using controller factory

the third approach uses controller factory. more complex, has advantages. in particular, if fxml file uses fx:include tags, controller factory reused when included fxml files loaded, controllers can have service object initialized well. managing included fxml files above 2 approaches possible, little convoluted.

the controller factory function maps class<?> controller should used (presumably 1 of class, though there requirement that). default controller factory invokes newinstance() on class<?> object (which why need no-arg constructor). here general controller factory implementation calls constructor taking service parameter if 1 exists, , calls no-arg constructor if not.

service service = ... ;  callback<class<?>, object> controllerfactory = type -> {     try {         (constructor<?> c : type.getconstructors()) {             if (c.getparametercount() == 1                  && c.getparametertypes()[0] == service.class) {                  return c.newinstance(service);             }         }         return type.newinstance();     } catch (exception e) {         throw new runtimeexception(e);    } }; 

you can create once , use fxml load (note references single service instance):

fxmlloader loader = new fxmlloader(getclass().getresource("path/to/fxml/file.fxml")); loader.setcontrollerfactory(controllerfactory); parent uiroot = loader.load(); 

this work fx:controller attribute if refers class constructor taking service parameter (such first controller example above).

if used dependency-injection frameworks, might interested in afterburner.fx adam bien. works setting controller factory examines controller class @inject annotations , sets values on controller, have annotate service field in controller , follow specific afterburner.fx naming conventions, , happens automagically.

i recommend this article, adam bien, discusses strategies communicating services controller (including handling concurrency issues).


Comments

Popular posts from this blog

facebook - android ACTION_SEND to share with specific application only -

python - Creating a new virtualenv gives a permissions error -

javascript - cocos2d-js draw circle not instantly -