那麼,我想在不同的環境下做同樣的事情......從一個主要服務啓動多個服務。 我已經覆蓋服務的所有方法,這是我的打印輸出:
- 服務只能從FX應用程序線程{從onFailed()方法}使用
服務不運行FX線程,但只能從FX線程調用。 因此,服務或任務中調用的所有服務和任務都不會執行。
這是我的解決方法:
public class FXComponentImporter extends Service<Void> implements JarImporter {
//Scanner<T> = Service<List<Class<T>>>
private Scanner<Node> nodeScanner = null;
private Scanner<Paint> paintScanner = null;
private Scanner<Animation> animationScanner = null;
private static int nodeCount = 0, paintCount = 0, animationCount = 0;
private final ObservableMap<String, Class<?>> foundComponents = FXCollections.observableHashMap();
public FXComponentImporter() {
this(null);
}
public FXComponentImporter(File file) {
if (file != null) {
try {
this.nodeScanner = new Scanner<>(file, Node.class);
this.paintScanner = new Scanner<>(file, Paint.class);
this.animationScanner = new Scanner<>(file, Animation.class);
} catch (IOException ex) {
Logger.getLogger(FXComponentImporter.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
File f = importJar();
try {
this.nodeScanner = new Scanner<>(f, Node.class);
this.paintScanner = new Scanner<>(f, Paint.class);
this.animationScanner = new Scanner<>(f, Animation.class);
} catch (IOException ex) {
Logger.getLogger(FXComponentImporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
this.scanningDone.bind(this.nodeScanningDone.and(this.paintScanningDone.and(this.animationScanningDone)));
this.scanningDone.addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) {
if(scanningDone.isBound()){
scanningDone.unbind();
}
start();
scanningDone.removeListener(this);
}
}
});
startScanning();
}
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
Map<String, Class<?>> map = new HashMap<>();
List<Class<Node>> nodes = new ArrayList<>();
List<Class<Paint>> paints = new ArrayList<>();
List<Class<Animation>> anims = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(1);
//Platform needed due to Service only accessed from FX thread
Platform.runLater(() -> {
try {
//FX Stuff done here
nodes.addAll(nodeScanner.getMatchingClasses());
paints.addAll(paintScanner.getMatchingClasses());
anims.addAll(animationScanner.getMatchingClasses());
} finally {
latch.countDown();
}
});
latch.await();
this.updateMessage("Scanning for Nodes ... ");
nodes.stream().forEach(n -> {
if(n != null){
map.putIfAbsent(n.getSimpleName(), n);
}
nodeCount++;
});
this.updateMessage("Found : " + nodeCount + " Nodes ... ");
this.updateMessage("Scanning for Paints ... ");
paints.stream().forEach(p -> {
if(p != null){
map.putIfAbsent(p.getSimpleName(), p);
}
paintCount++;
});
this.updateMessage("Found : " + paintCount + " Paints ... ");
this.updateMessage("Scanning for Animations ... ");
anims.stream().forEach(a -> {
if(a != null){
map.putIfAbsent(a.getSimpleName(), a);
}
animationCount++;
});
this.updateMessage("Found : " + animationCount + " Animations ... ");
foundComponents.putAll(map);
return null;
}
};
}
@Override
protected void executeTask(Task<Void> task) {
super.executeTask(task);
System.out.println(getClass().getSimpleName() + " is Executing " + task.getTitle());
}
@Override
protected void cancelled() {
super.cancelled();
System.out.println(getClass().getSimpleName() + " was Cancelled ... ");
}
@Override
protected void running() {
super.running();
System.out.println(getClass().getSimpleName() + " is Running ... ");
}
@Override
protected void ready() {
super.ready();
System.out.println(getClass().getSimpleName() + " is Ready! ... ");
}
@Override
protected void scheduled() {
super.scheduled();
System.out.println(getClass().getSimpleName() + " is Scheduled ... ");
}
@Override
protected void failed() {
super.failed();
System.out.println(getException().getMessage());
}
@Override
protected void succeeded() {
super.succeeded();
System.out.println("Importing Succeeded ... with: " + foundComponents.entrySet().size() + " results.\n");
foundComponents.forEach((s, c) -> {
System.out.println(c.getSuperclass().getSimpleName() + " >> " + s + " : " + c.getSimpleName());
});
}
@Override
public void restart() {
super.restart();
System.out.println(getClass().getSimpleName() + " is Restarting ... ");
}
private void startScanning() {
nodeScanner.stateProperty().addListener(nsl);
paintScanner.stateProperty().addListener(psl);
animationScanner.stateProperty().addListener(asl);
nodeScanner.start();
paintScanner.start();
animationScanner.start();
}
private final BooleanProperty scanningDone = new SimpleBooleanProperty(false);
private final BooleanProperty nodeScanningDone = new SimpleBooleanProperty(false);
private final BooleanProperty paintScanningDone = new SimpleBooleanProperty(false);
private final BooleanProperty animationScanningDone = new SimpleBooleanProperty(false);
private final ChangeListener nsl = new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
if (newValue.equals(State.SUCCEEDED)) {
nodeScanningDone.set(true);
nodeScanner.stateProperty().removeListener(this);
}
}
};
private final ChangeListener psl = new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
if (newValue.equals(State.SUCCEEDED)) {
paintScanningDone.set(true);
paintScanner.stateProperty().removeListener(this);
}
}
};
private final ChangeListener asl = new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
if (newValue.equals(State.SUCCEEDED)) {
animationScanningDone.set(true);
animationScanner.stateProperty().removeListener(this);
}
}
};
public ObservableMap<String, Class<?>> getFoundComponents() {
return foundComponents;
}
}
和我的接口,如果你想嘗試一下:
public interface JarImporter {
public static File defaultDirectory = new File(System.getProperty("user.home"));
public static final FileChooser.ExtensionFilter classfilter = new FileChooser.ExtensionFilter("Jar files", "*.jar");
static FileChooser defaultFileChooser(){
FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(classfilter);
fc.setInitialDirectory(defaultDirectory);
return fc;
}
public default File importJar(){
File jar = defaultFileChooser().showOpenDialog(null);
if(jar != null){
return jar;
}else{
return null;
}
}
}
希望這有助於..雖然只是看着問日期,並且是同時前...