我正在编写JavaFX应用程序,并且意识到FX线程上发生了太多事情。根本原因之一是gui事件(如按钮单击)在FX线程上产生了后端操作。实际上,刚收到事件后,我们就进入了FX线程,因此任何其他调用都将保留在该线程上。有什么方法可以简单地返回到MAIN应用程序线程,然后在需要时返回Platform.runLater,或者我必须使用例如RX或某些执行程序服务来处理它?</ p>
谢谢
答案 0 :(得分:4)
退出事件循环的方法非常简单-它只是Java。使用通常使用的任何东西-执行程序,队列等。
例如,要在“后台”完成某件事然后更新GUI,您可以执行类似的操作
final Executor backgroundWorker = Executors.newSingleThreadExecutor();
...
backgroundWorker.execute(()-> // from the EventLoop into the Worker
{
val result = doThatLongRunningTask();
Platform.runLater(() -> // back from the Worker to the Event Loop
{
updateUiWithResultOfLongRunningTask(result);
}
});
我通常希望将main
线程分配给事件循环,并使用自定义执行程序进行后台工作(因为后台工作是特定于应用程序的,因此可能需要更多线程等)。 / p>
如果出于任何异乎寻常的原因(实际上我没有想到),您都希望以相反的方式使用它:
因此,要将主线程用作执行程序,我们需要做的是:
public final class MyApp extends Application {
private static final Logger LOG = LoggerFactory.getLogger(MyApp.class);
private static final Runnable POISON_PILL = () -> {};
private final BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();
private final Executor backgroundWorker = this::execute;
private final Future<Void> shutdownFuture = new CompletableFuture<>();
private final Executor eventLoop = Executors.newSingleThreadExecutor();
/** Get background worker */
public Executor getBackgroundWorker() {
return backgroundWorker;
}
/** Request backgroun worker shutdown */
public Future shutdownBackgroundWorker() {
execute(POISON_PILL);
return shutdownFuture;
}
private void execute(Runnable task) {
tasks.put(task);
}
private void runWorkerLoop() throws Throwable {
Runnable task;
while ((task = tasks.take()) != POISON_PILL) {
task.run();
}
shutdownFuture.complete(null);
}
public static void main (String... args) throws Throwable {
final MyApp myApp = new MyApp(args);
LOG.info("starting JavaFX (background) ...");
eventLoop.execute(myApp::launch);
LOG.info("scheduling a ping task into the background worker...");
myApp.runLater(() -> {
LOG.info("#1 we begin in the event loop");
myApp.getBackgroundWorker().execute(() -> {
LOG.info("#2 then jump over to the background worker");
myApp.runLater(() -> {
LOG.info("#3 and then back to the event loop");
});
});
});
LOG.info("running the backgound worker (in the foreground)...");
myApp.runWorkerLoop();
}
}