I'd like to effectively "poll" on a JavaFX TableView so that if a job is created in the database by another user the current user would pick it up (let's say every 5 seconds).
I have tried using Timer;
new Timer().schedule(new TimerTask() {
#Override
public void run() {
try {
newI(connection, finalQuery, adminID);
} catch (SQLException e) {
e.printStackTrace();
}
}
}, 0, 5000);
However this gets the following error: Exception in thread "Timer-0" java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = Timer-0 which I assume means that it is not supported in JavaFX? How am I able to periodically update the TableView in JavaFX?
You can use a ScehduleService- something like this...
private class MyTimerService extends ScheduledService<Collection<MyDTO>> {
#Override
protected Task<Collection<MyDTO>> createTask() {
return new Task<Collection<MyDTO>>() {
#Override
protected Collection<MyDTO> call() throws ClientProtocolException, IOException {
//Do your work here to build the collection (or what ever DTO).
return yourCollection;
}
};
}
}
//Instead of time in your code above, set up your schedule and repeat period.
service = new MyTimerService () ;
//How long the repeat is
service.setPeriod(Duration.seconds(5));
//How long the initial wait is
service.setDelay(Duration.seconds(5));
service.setOnSucceeded(event -> Platform.runLater(() -> {
//where items are the details in your table
items = service.getValue();
}));
//start the service
service.start();
Related
How to set a Timer, say for 2 minutes, to try to connect to a Database then throw exception if there is any issue in connection?
So the first part of the answer is how to do what the subject asks as this was how I initially interpreted it and a few people seemed to find helpful. The question was since clarified and I've extended the answer to address that.
Setting a timer
First you need to create a Timer (I'm using the java.util version here):
import java.util.Timer;
..
Timer timer = new Timer();
To run the task once you would do:
timer.schedule(new TimerTask() {
#Override
public void run() {
// Your database code here
}
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);
To have the task repeat after the duration you would do:
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Your database code here
}
}, 2*60*1000, 2*60*1000);
// Since Java-8
timer.scheduleAtFixedRate(() -> /* your database code here */, 2*60*1000, 2*60*1000);
Making a task timeout
To specifically do what the clarified question asks, that is attempting to perform a task for a given period of time, you could do the following:
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Runnable r = new Runnable() {
#Override
public void run() {
// Database task
}
};
Future<?> f = service.submit(r);
f.get(2, TimeUnit.MINUTES); // attempt the task for two minutes
}
catch (final InterruptedException e) {
// The thread was interrupted during sleep, wait or join
}
catch (final TimeoutException e) {
// Took too long!
}
catch (final ExecutionException e) {
// An exception from within the Runnable task
}
finally {
service.shutdown();
}
This will execute normally with exceptions if the task completes within 2 minutes. If it runs longer than that, the TimeoutException will be throw.
One issue is that although you'll get a TimeoutException after the two minutes, the task will actually continue to run, although presumably a database or network connection will eventually time out and throw an exception in the thread. But be aware it could consume resources until that happens.
Use this
long startTime = System.currentTimeMillis();
long elapsedTime = 0L.
while (elapsedTime < 2*60*1000) {
//perform db poll/check
elapsedTime = (new Date()).getTime() - startTime;
}
//Throw your exception
Ok, I think I understand your problem now. You can use a Future to try to do something and then timeout after a bit if nothing has happened.
E.g.:
FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {
#Override
public Void call() throws Exception {
// Do DB stuff
return null;
}
});
Executor executor = Executors.newSingleThreadScheduledExecutor();
executor.execute(task);
try {
task.get(5, TimeUnit.SECONDS);
}
catch(Exception ex) {
// Handle your exception
}
new java.util.Timer().schedule(new TimerTask(){
#Override
public void run() {
System.out.println("Executed...");
//your code here
//1000*5=5000 mlsec. i.e. 5 seconds. u can change accordngly
}
},1000*5,1000*5);
[Android] if someone looking to implement timer on android using java.
you need use UI thread like this to perform operations.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
ActivityName.this.runOnUiThread(new Runnable(){
#Override
public void run() {
// do something
}
});
}
}, 2000));
i wrote a small application, which among other things makes a REST call to a JIRA REST API do download issues. I have a progress bar indicating the progress of the download. However, actually i need to make two REST calls. The first one needs to finished before the second one starts. Between them i need to update the UI.
Below is some example code:
// Loads the dialog from the fxml file and shows it
#FXML
public void showProgressDialog() {
mainApp.showDownloadProgressDialog();
}
// Retrieves some meta information
public void firstDownload() {
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
// do something
}
};
new Thread(task).start();
}
// Do some UI update
// Retrieves the actual issues
public void secondDownload() {
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
for (int i = 0; i < limit; i++) {
// so something
updateProgress((double) i / (double) limit, max);
}
}
};
new Thread(task).start();
}
// Do some UI update
How can i ensure that all functionality shown above is executed in exactly this order?
Thanks for any help!
You could use a EcecutorService with a single thread to control the scheduling:
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(task1);
service.submit(task2);
// shutdown after last submitted task
service.shutdown();
In my application, I load a table with data.
In this tab, one column come from a webservice which can make some times to answer.
So I treat this one in pool thread to avoid to block the screen like this:
final ObservableList<StockListBean> list = FXCollections
.observableArrayList();
list.addAll(stocksListMService.getStocksListRunning());
stocksList.setItems(list);
final ExecutorService executor = Executors.newFixedThreadPool(4);
for (final StockListBean stockListBean : list) {
executor.execute(new Task<Float>() {
#Override
protected Float call() throws Exception {
logger.debug("In jfx task for {}", stockListBean.getCode());
((StockListRunningBean)stockListBean).setActualPrice(stocksListMService.getActualPrice(stockListBean.getCode()));
columnActualPrice.setVisible(false);
columnActualPrice.setVisible(true);
return 0f;
}
});
}
Threads are well execute and data are well set in beans but I don't reach to refresh the tableView.
I try code in the snapshot. I try many other ways found on the web but nothing to do, the column is desperately empty.
If I keep the thread loop but without execute the service and set a default value, the column is not empty.
It's such a real problem with screen refresh.
How can I refresh this ?
Thanks.
Assuming your StockListRunningBean uses JavaFX observable properties, so that the TableView sees the changes, you shouldn't need to do anything additional to update the table. One problem with your code is that you're making changes to the UI (via changes to the StockListRunningBean price property) from a thread that's not the FX Application Thread.
Try this refactoring:
for (final StockListBean stockListBean : list) {
final int code = stockListBean.getCode(); // assuming int, change as required
final Task<Float> task = new Task<Float>() {
#Override
protected Float call() throws Exception {
logger.debug("In jfx task for {}", code);
return stocksListMService.getActualPrice(code);
}
};
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
((StockListRunningBean)stockListBean).setActualPrice(task.getValue());
}
});
executor.execute(task);
}
Again, this assumes that your StockListRunnerBean has a
public FloatProperty actualPriceProperty() {...}
method and that the table column is properly bound to it.
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!
How to set a Timer, say for 2 minutes, to try to connect to a Database then throw exception if there is any issue in connection?
So the first part of the answer is how to do what the subject asks as this was how I initially interpreted it and a few people seemed to find helpful. The question was since clarified and I've extended the answer to address that.
Setting a timer
First you need to create a Timer (I'm using the java.util version here):
import java.util.Timer;
..
Timer timer = new Timer();
To run the task once you would do:
timer.schedule(new TimerTask() {
#Override
public void run() {
// Your database code here
}
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);
To have the task repeat after the duration you would do:
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Your database code here
}
}, 2*60*1000, 2*60*1000);
// Since Java-8
timer.scheduleAtFixedRate(() -> /* your database code here */, 2*60*1000, 2*60*1000);
Making a task timeout
To specifically do what the clarified question asks, that is attempting to perform a task for a given period of time, you could do the following:
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Runnable r = new Runnable() {
#Override
public void run() {
// Database task
}
};
Future<?> f = service.submit(r);
f.get(2, TimeUnit.MINUTES); // attempt the task for two minutes
}
catch (final InterruptedException e) {
// The thread was interrupted during sleep, wait or join
}
catch (final TimeoutException e) {
// Took too long!
}
catch (final ExecutionException e) {
// An exception from within the Runnable task
}
finally {
service.shutdown();
}
This will execute normally with exceptions if the task completes within 2 minutes. If it runs longer than that, the TimeoutException will be throw.
One issue is that although you'll get a TimeoutException after the two minutes, the task will actually continue to run, although presumably a database or network connection will eventually time out and throw an exception in the thread. But be aware it could consume resources until that happens.
Use this
long startTime = System.currentTimeMillis();
long elapsedTime = 0L.
while (elapsedTime < 2*60*1000) {
//perform db poll/check
elapsedTime = (new Date()).getTime() - startTime;
}
//Throw your exception
Ok, I think I understand your problem now. You can use a Future to try to do something and then timeout after a bit if nothing has happened.
E.g.:
FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {
#Override
public Void call() throws Exception {
// Do DB stuff
return null;
}
});
Executor executor = Executors.newSingleThreadScheduledExecutor();
executor.execute(task);
try {
task.get(5, TimeUnit.SECONDS);
}
catch(Exception ex) {
// Handle your exception
}
new java.util.Timer().schedule(new TimerTask(){
#Override
public void run() {
System.out.println("Executed...");
//your code here
//1000*5=5000 mlsec. i.e. 5 seconds. u can change accordngly
}
},1000*5,1000*5);
[Android] if someone looking to implement timer on android using java.
you need use UI thread like this to perform operations.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
ActivityName.this.runOnUiThread(new Runnable(){
#Override
public void run() {
// do something
}
});
}
}, 2000));