java 更新ui,java thread立即更新UI
I have a javaFX application which visualizes compuational geometry algorithms. The execution of an algorithm happens in another thread, lets call it mainComputingThread.An algorithm can update the UI
I have a javaFX application which visualizes compuational geometry algorithms. The execution of an algorithm happens in another thread, lets call it mainComputingThread.
An algorithm can update the UI at any time by adding/removing/modifying shapes.
so the code will look like:
//do some computaions (1)
updateUI();
//do some more calculations (2)
What I want know is in the updateUI method to update the UI immediately and prevent the calling thread from running further (marked as (2)) until the UI update is done.
I thought about boolean guards. So the code could would look like:
updateUI(){
boolean guard = false;
Platform.runLater(new Runnable()
{
run(){
//do the actual update
guard = true;
}
});
while(guard==false);
}
I hope you get an idea of what I mean. I'm really curious if there's a better solution for this problem...
解决方案
Simple approach: block background thread until update is complete:
You need to update the UI on the FX Application Thread. Typically you do this by passing a plain Runnable to Platform.runLater(...).
If you want to wait for that ui update to complete before proceeding, instead create a FutureTask and pass it to Platform.runLater(...). Then you can call get() on the FutureTask, which will block until the task is complete:
private void updateUI() throws InterruptedException {
// actual work to update UI:
FutureTask updateUITask = new FutureTask(() -> {
// code to update UI...
}, /* return value from task: */ null);
// submit for execution on FX Application Thread:
Platform.runLater(updateUITask);
// block until work complete:
updateUITask.get();
}
This lets the FutureTask handle all the tricky work of waiting and notifying: it is always better to use a higher-level API for this kind of work when you can.
If you like, you can refactor this into a utility method, similarly to Dainesch's answer:
public class FXUtils {
public static void runAndWait(Runnable run) throws InterruptedException {
FutureTask task = new FutureTask<>(run, null);
Platform.runLater(task);
task.get();
}
}
Alternative approach: ensure that no more than one update is consumed during any frame rendering, blocking the background thread if an update is pending
Here is a somewhat different approach. Create a BlockingQueue with a capacity of 1 to hold the Runnables that update the UI. From your background thread, submit the Runnables to the blocking queue: since the blocking queue can hold at most one element, this will block if one is already pending.
To actually execute the updates in the queue (and remove them, so more can be added), use an AnimationTimer. This looks like:
private final BlockingQueue updateQueue = new ArrayBlockingQueue<>(1);
background thread code:
// do some computations...
// this will block while there are other updates pending:
updateQueue.put(() -> {
// code to update UI
// note this does not need to be explicitly executed on the FX application
// thread (no Platform.runLater()). The animation timer will take care of that
});
// do some more computations
Create the timer to consume the updates:
AnimationTimer updateTimer = new AnimationTimer() {
@Override
public void handle(long timestamp) {
Runnable update = updateQueue.poll();
if (update != null) {
// note we are already on the FX Application Thread:
update.run();
}
}
};
updateTimer.start();
This basically ensures that no more than one update is ever scheduled at any time, with the background thread blocking until any pending updates are consumed. The animation timer checks (without blocking) for pending updates on each frame rendering, ensuring that every update is executed. The nice thing about this approach is that you can increase the size of the blocking queue, effectively keeping a buffer of pending updates, while still ensuring no more than one update is consumed during any single frame rendering. This might be useful if there are occasional computations that take longer than others; it gives these computations a chance to be calculated while others are waiting to be executed.
更多推荐
所有评论(0)