JavaFX FadeTransition.onSetOnFinished with CountdownLatch does not work as expected - animation

I'm staring at my code and I'm pretty stuck with one issue:
I want to make a fade out transition, and i want to block current thread, while the fade transition is running.
So, my attempt was to create a CountDownLatch, which blocks the thread, until the transition.setOnFinished() is called, where I make a latch.countdown(). In short: i want to make sure, that the transition is always visible in full length.
Seemed pretty straight forward to me, but...
The setOnFinished() doesn't get called, BECAUSE the current thread mentioned above is blocked by the countdown latch.
How can i solve this issue? Thx in advance.
private void initView() {
Rectangle rect = new Rectangle();
rect.widthProperty().bind(widthProperty());
rect.heightProperty().bind(heightProperty());
rect.setFill(Color.BLACK);
rect.setOpacity(0.8f);
getChildren().add(rect);
MyUiAnimation animator = new MyUiAnimation();
fadeInTransition = animator.getShortFadeInFor(this);
fadeOutTransition = animator.getShortFadeOutFor(this);
fadeOutTransition.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
Platform.runLater(new Runnable() {
#Override
public void run() {
latch.countDown();
setVisible(false);
}
});
}
});
}
public void hide() {
fadeInTransition.stop();
if (isVisible()) {
latch = new CountDownLatch(1);
fadeOutTransition.playFromStart();
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

You can only modify and query the active scene graph on the JavaFX application thread. All of your code works with the scene graph, so it all must be run on the JavaFX application thread. If everything is already running on the JavaFX application thread, there is no reason for concurrency related constructs in your code.
If you use blocking calls like latch.await(), you will block the JavaFX application thread, which will prevent any rendering, layout or animation steps to run. CountdownLatch should not be used in this context and should be removed from the code.
Calling Platform.runLater is unnecessary as it's purpose is to run code on the JavaFX application thread, and you are on the JavaFX application thread already. Platform.runLater should not be used in this context and should be removed from the code.

Related

JavaFX image not changing when function is called by Platform.runLater

I have a function to change an image and its opacity in a JavaFX GUI:
private static Image image = null;
private static ImageView imageView = new ImageView();
// some code to add image in GUI
public static void changeImage() {
imageView.setOpacity(0.5);
imageView.setImage(null);
}
When I call this function within the JavaFX instance, the image disappears or is changing if I use an image instead of null for setImage(). I tried calling the function by pressing a button.
In this case all works as I expected.
When I call this function from another class, the actual image will change its opacity, but the image itself is never changing. I call the function the following way:
public static void changeImg() {
Platform.runLater(() -> FX_Gui.changeImage());
}
Changing labels, progess bars... all works, but I did not manage to change an image.
There's a lot of aspects to this question that don't make sense.
Generally speaking, the GUI in JavaFX is intended to be self-contained and non-linear in it's execution. Programming an outside method to assume some state of the GUI, and then to directly manipulate the GUI based on that assumption is not the correct approach. So any attempt to know the state of the GUI by kludging in a Thread.sleep() call is inherently incorrect.
The new JFXPanel() call is not needed, as Application.launch() will initialize JavaFX. Presumably, this was added before the sleep(500) was put in, since calling changeImg() would fail if run immediately after the Thread.start() command, since the launch() wouldn't have time to even start yet.
As has been noted, having some kind of startup image that's replaced once the screen completes initialization should be done from within the FX_Min.start(Stage) method, although it's highly unlikely that you'd even see the first image.
The question seems to be aimed at designing a kind of application where the GUI is just some small part of it and the main application is going to go on to do lengthy processing and then trigger the GUI to something in response to the results of that processing. Or perhaps the main application is monitoring an external API and feeding updates to GUI periodically. In most cases, however, the GUI is usually initialized so that it can take control of the operation, launching background threads to do the lengthy processing and using JavaFX tools to handle the triggering of GUI updates and intake of results.
In the instance that the design really needs to have something other than the GUI be the central control, then use of Application does not seem appropriate. It is, after all, designed to control the Application, and monitors the status of the GUI once it's been launched to shut everything down when the GUI is closed. This is why the OP had to put the Application.launch() call in a separate thread - launch() doesn't return until the GUI shuts down.
If the application outside of the GUI is going to control everything then it's best to manually start JavaFX with Platform.startup(), and handle all the monitoring manually. The following code doesn't do any monitoring, but it does start up the GUI and change the image without any issues:
public class Control_Min {
public static void main(String[] args) {
Platform.startup(() -> new Fx_Min().start(new Stage()));
Platform.runLater(() -> Fx_Min.changeImage());
}
}
Note that no changes are required to the OP's code in Fx_Min. However, there's no reason for Fx_Min to extend Application any more, and the code from its start() method can be placed anywhere.
It should be further noted that, although this works, it's really way outside the norm for JavaFX applications. It's possible that the OP's situation really does require this kind of architecture, but that would place it into a very small minority of applications. Designing the application around Application.launch() and initiating lengthy processing in background threads through the JavaFX tools provided is almost always a better approach.
OK, so given new information from the OP it's clear that this should be based on Application and that the GUI should launch some kind of socket listener that would presumably block waiting for input.
Anything that blocks can't run on the FXAT, and there needs to be a way to allow the socket listener to communicate back to the GUI when it receives data. Ideally, the socket listener should be JavaFX unaware, and just plain Java.
IMO, the best way to do this is to provide a Consumer to accept information from the socket listener, and to pass it to the socket listener in it's constructor. That way, the GUI knows nothing about the nature of the socket listener except that it has a dependency on requiring a message consumer. Similarly, the socket listener has no knowledge about what invoked it, just that it has given it a message consumer.
This limits your coupling, and you are free to write your GUI without worrying about any of the inner workings of the socket listener, and visa versa.
So here's the GUI, cleaned up and simplified a bit so that the socket listener stuff is easier to follow. Basically, the GUI is just going to throw the message from the socket listener into a Text already on the screen. The message consumer handles the Platform.runLater() so that the socket listener isn't even aware of it:
public class Fx_Min extends Application {
#Override
public void start(Stage primaryStage) {
ImageView imageView = new ImageView(new Image("/images/ArrowUp.png"));
Text text = new Text("");
primaryStage.setScene(new Scene(new VBox(10, imageView, text), 800, 600));
primaryStage.setResizable(true);
primaryStage.show();
imageView.setImage(new Image("/images/Flag.png"));
new SocketListener(socketMessage -> Platform.runLater(() -> text.setText(socketMessage))).startListening();
}
public static void main(String[] args) {
launch(args);
}
}
Here's the socket listener. Clearly, this isn't going to listen on a socket, but it loops around a sleep() to simulate action happening on the Pi. The message format here is String, just to keep everything simple, but obviously this is the worse possible choice for an actual implementation of this. Build a special message class:
public class SocketListener {
private Consumer<String> messageConsumer;
public SocketListener(Consumer<String> messageConsumer) {
this.messageConsumer = messageConsumer;
}
public void startListening() {
Thread listenerThread = new Thread(() -> listenForIRCommand());
listenerThread.setDaemon(true);
listenerThread.start();
}
private void listenForIRCommand() {
for (int x = 0; x < 100; x++) {
try {
Thread.sleep(5000);
messageConsumer.accept("Station " + x);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
It should be really clear that since the call to listenForIRCommand() is executed from inside a background thread, that it's completely freed from any JavaFX contstraints. Anything that generally possible in Java can be done from there without worrying about it's impact on the GUI.
In the meantime I found out that the reason for not changing the image is that I run changeImage() before the initialization of the GUI is completed. If I wait about 500 mS before I sent the changeImage() command all works fine.
Below is the minimal code that demonstrates the issue I had:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
public class Control_Min {
public static void changeImg() {
Platform.runLater(() -> Fx_Min.changeImage());
}
public static void main(String[] args) {
new Thread() {
public void run() {
Application.launch(Fx_Min.class);
}
}.start();
// JFXPanel will initialize the JavaFX toolkit.
new JFXPanel();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
changeImg();
}
}
And the Gui itself:
public class Fx_Min extends Application {
private static Stage stage;
private static GridPane rootPane;
private static Scene scene;
private static Image image = null;
private static ImageView imageView = new ImageView();
#Override
public void start(Stage primaryStage) {
stage = primaryStage;
rootPane = new GridPane();
scene = new Scene(rootPane,800,600);
try {
image = new Image(new FileInputStream("C:\\Users\\Peter\\eclipse-workspace\\FX_Test\\src\\application\\Image1.jpg"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
imageView.setImage(image);
rootPane.add(imageView, 1, 0);
stage.setScene(scene);
stage.setResizable(true);
stage.show();
System.out.println("Gui is ready");
}
public static void changeImage() {
try {
image = new Image(new FileInputStream("C:\\Users\\Peter\\eclipse-workspace\\FX_Test\\src\\application\\Image2.jpg"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
imageView.setImage(image);
System.out.println("Image Changed");
}
public static void main(String[] args) {
launch(args);
}
}
This code works fine.
In the console I get:
Gui is ready
Image Changed
When I remove the Thread.sleep(500) the image will not change.
In the console I get:
Image Change
Gui is ready
My conclusion is that I have send the runlater method before the FX runtime has been initialized.
(Have not fixed the static issue yet as this was not the issue. I will do in my original program later.)
My task is the following:
I program a GUI for my internet radio player on my PC.
The GUI controls the radio and polls what is playing.
I want to control the radio by an IR remote control too.
I have already a Raspberry Pi that communicates with the remote.
Therefore, my plan is to run a server socket on the PC, that receives the commands from the Raspberry Pi.
The server will run in its own thread. I want to use the runLater command to update the GUI.
Is there a better way to update the GUI from the server?
Goal is that the GUI will update immediately when I press a button on the remote.
With my latest learnings about JavaFX I will start the application now directly in the FX class and get the server thread started from the FX class

How to enable and disable a progress indicator when using JMS in javafx8

on action i send a message to a jms topic to process data and i have a call back method which gets called when the data is ready and loads a TableView.
public void onEnter(ActionEvent actionEvent) throws IOException, InterruptedException {
new Thread() {
public void run() {
Platform.runLater(() -> {
progressIndicator.setVisible(true);
scrollPane.setDisable(true);
});
// Construct the message and publish it to a topic
};
}.start();
}
}
public void callBackMethod(List<Object> list ) {
progressIndicator.setVisible(false);
scrollPane.setDisable(false);
//load data in the table
}
This does what i want, but what if something goes wrong at the messaging system end , the call back never gets called and the UI component will be disabled forever .
Any suggestions to improve this will be helpful.
Presumably, the messaging system is going to throw some kind of exception if it fails to send the message, so you'll need a way to catch that and recover properly. If you use the JavaFX "Task" class, then you'll get events when that happens. You'll still have to deal with a failure at the receiving end, or implement some kind of a time-out, if that's appropriate.
Also, you're starting up a thread and then immediately tossing a job onto the FXAT with RunLater. The onEnter event handler, by definition, is already running on the FXAT, so you can just do your GUI stuff before you start up the thread (or Task, as I suggest). Here's a sample that shows how to launch the Task, and clean up if it fails with an exception:
public class SampleTask extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
BorderPane root = new BorderPane();
ProgressIndicator progressIndicator = new ProgressIndicator(0);
ScrollPane scrollPane = new ScrollPane();
Button button = new Button("Start");
root.setTop(progressIndicator);
root.setCenter(scrollPane);
progressIndicator.setVisible(false);
root.setBottom(button);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
button.setOnAction(actionEvent -> {
progressIndicator.setVisible(true);
scrollPane.setDisable(true);
Task<Void> testTask = new Task<Void>() {
#Override
protected Void call() throws Exception {
// Send the message
return null;
}
};
testTask.setOnFailed(event -> {
progressIndicator.setVisible(false);
scrollPane.setDisable(false);
});
new Thread(testTask).start();
});
}
}

Stop main thread until all events on JavaFX event queue have been executed

While debugging an application I would like the main thread to wait after each Runnable I put on the JavaFX event queue using
Platform.runLater(new Runnable()... )
to wait until it has been executed (i.e. is visible). However there are two twists here:
First, it is not really a standard, GUI driven JavaFX app. It is rather a script showing and updating a JavaFX stage every now an then. So the structure looks something like this:
public static void main(String [] args){
//do some calculations
SomeView someView = new SomeView(data); //SomeView is basically a wrapper for a stage
PlotUtils.plotView(someView) //displays SomeView (i.e. the stage)
//do some more calculations
someView.updateView(updatedData)
//do some more calculations
}
public class SomeView {
private static boolean viewUpdated = false;
private ObservableList<....> observableData;
public void updateView(Data data){
Platform.runLater(new Runnable() {
#Override
public void run() {
observableData.addAll(data);
boolean viewUpdated = true;
}
});
//If configured (e.g using boolean switch), wait here until
//the Runnable has been executed and the Stage has been updated.
//At the moment I am doing this by waiting until viewUpdated has been
//set to true ... but I am looking for a better solution!
}
}
Second, it should be easy to disable this "feature", i.e. to wait for the Runnable to be executed (this would be no problem using the current approach but should be possible with the alternative approach as well).
What is the best way to do this?
E.g. is there something like a blocking version to execute a Runnable on the JavaFX thread or is there an easy way to check whether all events on the event queue have been executed/ the eventqueue is empty....?
There's also PlatformImpl.runAndWait() that uses a countdown latch so long as you don't call it from the JavaFX thread
This is based on the general idea from JavaFX2: Can I pause a background Task / Service?
The basic idea is to submit a FutureTask<Void> to Platform.runLater() and then to call get() on the FutureTask. get() will block until the task has been completed:
// on some background thread:
Runnable runnable = () -> { /* code to execute on FX Application Thread */};
FutureTask<Void> task = new FutureTask<>(runnable, null);
Platform.runLater(task);
task.get();
You must not execute this code block on the FX Application Thread, as this will result in deadlock.
If you want this to be easily configurable, you could do the following:
// Wraps an executor and pauses the current thread
// until the execution of the runnable provided to execute() is complete
// Caution! Calling the execute() method on this executor from the same thread
// used by the underlying executor will result in deadlock.
public class DebugExecutor implements Executor {
private final Executor exec ;
public DebugExecutor(Executor executor) {
this.exec = executor ;
}
#Override
public void execute(Runnable command) {
FutureTask<Void> task = new FutureTask<>(command, null);
exec.execute(command);
try {
task.get();
} catch (InterruptedException interrupt) {
throw new Error("Unexpected interruption");
} catch (ExecutionException exc) {
throw new RuntimeException(exc);
}
}
}
Now in your application you can do:
// for debug:
Executor frontExec = new DebugExecutor(Platform::runLater);
// for production:
// Executor frontExec = Platform::runLater ;
and replace all the calls to
Platform.runLater(...) with frontExec.execute(...);
Depending on how configurable you want this, you could create frontExec conditionally based on a command-line argument, or a properties file (or, if you are using a dependency injection framework, you can inject it).

Android basics: running code in the UI thread

In the viewpoint of running code in the UI thread, is there any difference between:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
or
MainActivity.this.myView.post(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
and
private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
protected void onPostExecute(Bitmap result) {
Log.d("UI thread", "I am the UI thread");
}
}
None of those are precisely the same, though they will all have the same net effect.
The difference between the first and the second is that if you happen to be on the main application thread when executing the code, the first one (runOnUiThread()) will execute the Runnable immediately. The second one (post()) always puts the Runnable at the end of the event queue, even if you are already on the main application thread.
The third one, assuming you create and execute an instance of BackgroundTask, will waste a lot of time grabbing a thread out of the thread pool, to execute a default no-op doInBackground(), before eventually doing what amounts to a post(). This is by far the least efficient of the three. Use AsyncTask if you actually have work to do in a background thread, not just for the use of onPostExecute().
I like the one from HPP comment, it can be used anywhere without any parameter:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
There is a fourth way using Handler
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
The answer by Pomber is acceptable, however I'm not a big fan of creating new objects repeatedly. The best solutions are always the ones that try to mitigate memory hog. Yes, there is auto garbage collection but memory conservation in a mobile device falls within the confines of best practice.
The code below updates a TextView in a service.
TextViewUpdater textViewUpdater = new TextViewUpdater();
Handler textViewUpdaterHandler = new Handler(Looper.getMainLooper());
private class TextViewUpdater implements Runnable{
private String txt;
#Override
public void run() {
searchResultTextView.setText(txt);
}
public void setText(String txt){
this.txt = txt;
}
}
It can be used from anywhere like this:
textViewUpdater.setText("Hello");
textViewUpdaterHandler.post(textViewUpdater);
As of Android P you can use getMainExecutor():
getMainExecutor().execute(new Runnable() {
#Override public void run() {
// Code will run on the main thread
}
});
From the Android developer docs:
Return an Executor that will run enqueued tasks on the main thread associated with this context. This is the thread used to dispatch calls to application components (activities, services, etc).
From the CommonsBlog:
You can call getMainExecutor() on Context to get an Executor that will execute its jobs on the main application thread. There are other ways of accomplishing this, using Looper and a custom Executor implementation, but this is simpler.
If you need to use in Fragment you should use
private Context context;
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
((MainActivity)context).runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
instead of
getActivity().runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
Because There will be null pointer exception in some situation like pager fragment
use Handler
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Kotlin version:
Handler(Looper.getMainLooper()).post {
Toast.makeText(context, "Running on UI(Main) thread.", Toast.LENGTH_LONG).show()
}
Or if you are using Kotlin coroutines:
inside coroutine scope add this:
withContext(Dispatchers.Main) {
Toast.makeText(context, "Running on UI(Main) thread.", Toast.LENGTH_LONG).show()
}

Live SDK Windows Phone 7 GetCompleted callback in UI thread?

public class SyncHelper
{
private LiveConnectClient client;
public event EventHandler SyncStarted;
public event EventHandler SyncCompleted;
public SyncHelper(LiveConnectClient client)
{
this.client = client;
}
public void TrySync()
{
Debug.WriteLine("Beginning sync");
OnSyncStarted();
client.GetCompleted += OnGetCompleted;
client.GetAsync("me/skydrive/files");
}
private void OnGetCompleted(object sender, LiveOperationCompletedEventArgs e)
{
Thread.Sleep(10000);
Debug.WriteLine("Get Completed");
client.GetCompleted -= OnGetCompleted;
OnSyncCompleted();
Debug.WriteLine("Sync completed");
}
private void OnSyncStarted()
{
if (SyncStarted != null)
SyncStarted(this, new EventArgs());
}
private void OnSyncCompleted()
{
if (SyncCompleted != null)
SyncCompleted(this, new EventArgs());
}
}
The function OnGetCompleted is being called in the UI thread and the UI is unresponsive. From whatever I know, I thought these callbacks would work in a different thread and we would have to use the displatcher to post it to the UI thread. Any thoughts? Help!
The GetAsync call is likely using a background thread to do the actual fetch, but then it's trying to help you by calling the Completed callback in the original thread context so you don't have to use a Dispatcher.
Why are you putting in a Sleep(10000) anyway? The callback says "hey, I'm done". At that point you should update the UI if you want. If you need to do further processing that takes significant time, spawn a background thread, threadpool task or use another asynchronous call with another callback.

Resources