For JavaFX UI node, if I register an event handler:
final MenuItem buyItem = new MenuItem("Buy");
buyItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String symbol = row.getItem().getSymbol();
String instrumentID = row.getItem().getInstrumentID();
.....
}
);
I can assume code inside handle() will always be executed in JavaFX application Thread, so there is no need to wrap them inside Platform. runLater.
But when I work with javafx.concurrent.Task:
import javafx.concurrent.Task;
public class BuyTask extends Task<Map<String, Object>> {
......
}
BuyTask buyTask = new BuyTask(this.api, params);
Thread buyThread = new Thread(buyTask);
buyThread.start();
buyTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(final WorkerStateEvent workerStateEvent) {
Map<String, Object> result = (Map) workerStateEvent.getSource().getValue();
.......
Platform.runLater(new Runnable() {
#Override public void run() {
portfolioService.restart();
}
});
}
}
In which thread is the task's event handler executed in? As I need to do perform restart on a javafx.concurrent.ScheduledService -> portfolioService.restart() which mentioned must be done in JavaFX Application Thread, I wrap it inside Platform.runLater.
But is it required? Will this task event handler always being executed in JavaFX Application Thread as well? Thanks!
The JavaFX documentation for Task has the answer:
Because the Task is designed for use with JavaFX GUI applications, it ensures that every change to its public properties, as well as change notifications for state, errors, and for event handlers, all occur on the main JavaFX application thread.
So - no, there is no need to wrap the call with Platform.runLater.
Related
I'm making a program which sends some data to the Matlab and receives output from matlab. To do that, I used matlabcontrol library.
Problem
After I click Java FX application button to submit data, matlabcontrol opens Matlab for further calculations. But when java opens the matlab, Java FX application stuck with wait cursor.Then starts to work again after Matlab finishes the process of calculation.
What I did
public void runner()
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
firstFunc();
}
});
Platform.runLater(new Runnable()
{
#Override
public void run()
{
secondFunc();
}
});
}
public void firstFunc()
{
// This function controls UI while Matlab does it's calculations
double progress = 0.2;
progressLabel.setText(progress*100+"% Completed");
progressBar.setProgress(progress);
}
public void secondFunc()
{
// This method creates matlab connection and handle matlab
firstClass mainFunc = new firstClass(pathSelected);
mainFunc.func();
}
So I used Platform runLater to run two methods separately. But still my program stuck with wait cursor when Matlab starts to functioning.
I also used threads to run these functions in parallel. But had the same issue. How can I correct this. Any help?
Update
As described in this question, I did use service and task with countdownlatch. But still didn't get what I wanted. In there,
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Background work
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//FX Stuff done here
firstFunc();
}finally{
latch.countDown();
}
}
});
latch.await();
//Keep with the background work
// I added matlab calling function here.
secondFunc();
return null;
}
};
}
};
service.start();
latch await and let background work to carry on. But in my case, my FX application shows a progress bar. So it should always update while background task happens. In here, it finishes FX task and moves to background task. I didn't get what I wanted. please help.
I had to use Service, Task and CountDownLatch to accomplish this task as I mentioned in Question Update part.
Also, I had to run another task inside the firstFunc, where I did update the progress. Like in this answer.
I come from .NET environment where event listening is pretty easy to implement even for a beginner. But this time I have to do this in Java.
My pseudo code:
MainForm-
public class MainForm extends JFrame {
...
CustomClass current = new CustomClass();
Thread t = new Thread(current);
t.start();
...
}
CustomClass-
public class CustomClass implements Runnable {
#Override
public void run()
{
//...be able to fire an event that access MainForm
}
}
I found this example but here I have to listen for an event like in this other one. I should mix them up and my skill level in Java is too low.
Could you help me elaborating a optimal solution?
I think that what you are looking for is SwingWorker.
public class BackgroundThread extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
// background calculation, will run on background thread
// publish an update
publish("30% calculated so far");
// return the result of background task
return 9;
}
#Override
protected void process(List<String> chunks) { // runs on Event Dispatch Thread
// if updates are published often, you may get a few of them at once
// you usually want to display only the latest one:
System.out.println(chunks.get(chunks.size() - 1));
}
#Override
protected void done() { // runs on Event Dispatch Thread
try {
// always call get() in done()
System.out.println("Answer is: " + get());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Of course when using Swing you want to update some GUI components instead of printing things out. All GUI updates should be done on Event Dispatch Thread.
If you want to only do some updates and the background task doesn't have any result, you should still call get() in done() method. If you don't, any exceptions thrown in doInBackground() will be swallowed - it is very difficult to find out why the application is not working.
I would like to update a Label in a JavaFX application so that the text changes multiple times as the method runs:
private void analyze(){
labelString.setValue("Analyzing"); // (labelString is bound to the Label during initialization)
// <Some time consuming task here>
labelString.setValue("Analysis complete!");
}
But when I run this, the label does not update until the task finishes, and just displays whatever it was before until the analyze() method returns.
How can I force update the label so that it will show "Analyzing" in the beginning followed by "Analysis complete!" when the task is complete?
Assuming you are invoking your analyze() method on the FX Application Thread (e.g. in an event handler), your time consuming code is blocking that thread and preventing the UI from updating until it is complete. As #glen3b says in the comments, you need to use an external thread to manage this code.
JavaFX provides a Task API which helps you do this. In particular, it provides methods which invoke code on the Java FX Application thread for you, allowing you to update the UI safely from your background Task.
So you can do something like
private void analyze() {
Task<Void> task = new Task<Void>() {
public Void call() {
updateMessage("Analyzing");
// time consuming task here
updateMessage("Analysis complete");
}
};
labelString.bind(task.messageProperty());
new Thread(task).start();
}
If you need to unbind the StringProperty when the task is complete, you can do
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
labelString.unbind();
}
});
I'm using ListenableFuture from Guava, and one nice thing about them is that one pass Executor to the Futures.addCallback method, that is, ask to execute the callback on a given thread/executor.
In my Android application, I want to be able to start the asynchronous execution based on ListenableFuture in the UI thread, and schedule a callback which is also executed also on the UI thread. Therefore, I'd like to somehow submit the UI thread executor to the Futures.addCallback method mentioned above. How to achieve that?
Or, in other words, I want to have an executor for the UI thread. Is it available already in Android, or, if I have to create my own, how do I do that?
EDIT: As an extension to this question, is it possible to do same thing, but not just with UI thread, but with any particular thread, where the call to async method is made?
I would be happy to know how to achieve the same effect without resorting to the Android-specific stuff like Handler and Looper, just with pure Java.
I think I've see some implementation doing that. The basic Idea is roughly
class UiThreadExecutor implements Executor {
private final Handler mHandler = new Handler(Looper.getMainLooper());
#Override
public void execute(Runnable command) {
mHandler.post(command);
}
}
You can delegate to run anything in the main thread by passing it to a handler for the main thread.
Edit: https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/android/MainThreadExecutor.java for example
Edit2: You can configure the handler like e.g. SensorManager#registerListener(..., Handler handler) allows you to do.
class HandlerThreadExecutor implements Executor {
private final Handler mHandler;
public HandlerThreadExecutor(Handler optionalHandler) {
mHandler = optionalHandler != null ? optionalHandler : new Handler(Looper.getMainLooper());
}
#Override
public void execute(Runnable command) {
mHandler.post(command);
}
}
The advantage over using the current thread's looper is that it makes it explicit which Looper you use. In your solution you take the Looper of whatever thread calls new ExecuteOnCaller() - and that's often not the thread you run code in later.
I would be happy to know how to achieve the same effect without resorting to the Android-specific stuff like Handler and Looper, just with pure Java.
Looper, Handler and the message queue behind all that logic are made of mostly pure Java. The problem with a generic solution is that you can't "inject" code to run into a thread. The thread must periodically check some kind of task queue to see if there is something to run.
If you write code like
new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
System.out.println("Hello");
}
}
}).start();
Then there is no way to make that thread do anything else but constantly print "Hello". If you could do that it would be like dynamically inserting a jump to other code into the program code. That would IMO be a terrible idea.
final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
Runnable codeToRunInThisThread = queue.take();
codeToRunInThisThread.run();
}
} catch (InterruptedException ignored) {}
}
}).start();
On the other hand is a simple thread that loops forever on a queue. The thread could do other tasks in between but you have to add a manual check into the code.
And you can send it tasks via
queue.put(new Runnable() {
#Override
public void run() {
System.out.println("Hello!");
}
});
There is no special handler defined here but that's the core of what Handler & Looper do in Android. Handler in Android allows you to define a callback for a Message instead of just a Runnable.
Executors.newCachedThreadPool() and similar do roughly the same thing. There are just multiple threads waiting on code in a single queue.
As an extension to this question, is it possible to do same thing, but not just with UI thread, but with any particular thread, where the call to async method is made?
The generic answer is No. Only if there is a way to inject code to run in that thread.
Based on asnwer from #zapl, here is my implementation, which also answers the edited (extended) question: https://gist.github.com/RomanIakovlev/8540439
Figured out I'll also put it here, in case if link will rot some day:
package com.example.concurrent;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executor;
/**
* When the calling thread has a Looper installed (like the UI thread), an instance of ExecuteOnCaller will submit
* Runnables into the caller thread. Otherwise it will submit the Runnables to the UI thread.
*/
public class ExecuteOnCaller implements Executor {
private static ThreadLocal<Handler> threadLocalHandler = new ThreadLocal<Handler>() {
#Override
protected Handler initialValue() {
Looper looper = Looper.myLooper();
if (looper == null)
looper = Looper.getMainLooper();
return new Handler(looper);
}
};
private final Handler handler = threadLocalHandler.get();
#Override
public void execute(Runnable command) {
handler.post(command);
}
}
My pattern to use it would be like this:
/**
* in SomeActivity.java or SomeFragment.java
*/
Futures.addCallback(myModel.asyncOperation(param), new FutureCallback<Void>() {
#Override
public void onSuccess(Void aVoid) {
// handle success
}
#Override
public void onFailure(Throwable throwable) {
// handle exception
}
}, new ExecuteOnCaller());
Use com.google.android.gms.tasks.TaskExecutors.MAIN_THREAD.
An Executor that uses the main application thread.
Source: Android docs
The tasks APIs are part of Google Play services since version 9.0.0.
For Android UI thread executor use:
ContextCompat.getMainExecutor(context)
To address your question and extended question to create an Executor that simply runs on the current thread and avoids Android classes:
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
See documentation: https://developer.android.com/reference/java/util/concurrent/Executor
I am wanting to execute a task at a regular interval from my JavaFX application. The task pulls data from a remote stream.
While I know I could use a Timer as suggested below:
JavaFX periodic background task
I believe this should be able to be done using the JavaFX Service object. There's mention in the Javadoc about specifying a custom executor (ScheduledThreadPoolExecutor comes to mind here), but how would one specify the period and delay? Ideally, this would use the Service's usual start, reset, restart, and state bindings...
public class MyFirstLineService extends Service<String> {
private StringProperty url = new SimpleStringProperty(this, "url");
public final void setUrl(String value) { url.set(value); }
public final String getUrl() { return url.get(); }
public final StringProperty urlProperty() { return url; }
public MyFirstLineService() {
setExecutor(new ScheduledThreadPoolExecutor());
}
protected Task createTask() {
final String _url = getUrl();
return new Task<String>() {
protected String call() throws Exception {
URL u = new URL(_url);
BufferedReader in = new BufferedReader(
new InputStreamReader(u.openStream()));
String result = in.readLine();
in.close();
return result;
}
};
}
}
A ScheduledService was requested in the JavaFX issue tracker - RT18702.
The tracker includes source for a preliminary implementation which has not been incorporated in the 2.2 branch. If needed, you could take a look at that source and see if it helps improve on your solution.
I have found a way to do this, building on the comments from sarcan above...
One can create a Timeline object, normally used to animate UI elements, as a timer that operates on the FX Application Thread. Using this its possible to restart the Service object, which then performs the long-running operation on a background thread, yet preserves property access and updates via the FX Application Thread bindings.
Ex:
final MyFirstLineService svc = new MyFirstLineService();
final Duration oneFrameAmt = Duration.seconds(5);
final KeyFrame oneFrame = new KeyFrame(oneFrameAmt,
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent evt) {
svc.restart();
}
});
Timeline timer = TimelineBuilder.create()
.cycleCount(Animation.INDEFINITE)
.keyFrames(oneFrame)
.build();
timer.playFromStart();
Run into the same problem. An example with ScheduledThreadPoolExecutor could be:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
Service s = new Service(){
#Override
protected Task<String> createTask() {
return new Task<String>() {
#Override
protected String call() throws Exception {
// code...
}
};
}
}
// created tasks shall be run in thread pool
s.setExecutor(executor);
// start the service the first time
s.start();
// restart the service every 5 seconds
s.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
// need runLater here since trigger needs to be in the javaFX thread
Platform.runLater(new Runnable() {
#Override
public void run() {
checker.restart();
}
});
}
}, 0, 5, TimeUnit.SECONDS);
}
Could be solved with a Timer but then you lost the JavaFX data binding capability (as you already mentioned). Looking forward to Java8!