How to update TableView items outside JavaFX Thread - java

I have a table view that lists user's friends and I need to update it every 5 seconds with data that I retrieve from database.
This is the code I use:
Main.java
private List<Friend> userFriends;
fx controller:
ObservableList<FriendWrapper> friendList = FXCollections.observableList(
new ArrayList<FriendWrapper>());
private void updateFriendList() {
new Thread(new Runnable() {
public void run() {
while (Params.loggedUser != null) {
Main.setUserFriends(Params.dao.listUserFriends(Params.loggedUser));
friendList.clear();
for (Friend friend : Main.getUserFriends()) {
friendList.add(new FriendWrapper(friend.getFriendName(), friend.getOnline(), friend.getFriendId(), friend.getWelcomeMessage()));
}
Params.dao.updateOnlineStatus(Params.loggedUser, 3);
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "updateFriendList").start();
}
Friend is database model. FriendWrapper is object used for table rows.
however I get IllegalStateException: Not on FX application thread on line friendList.clear();
How can I change the items of TableView from a thread running in the background?

Instead of a quick Platform.runLater() hack, you should probably make use of the Task class:
protected class LoadFriendsTask extends Task<List<FriendWrapper>>
{
#Override
protected List<FriendWrapper> call() throws Exception {
List<Friend> database = new ArrayList<>(); //TODO fetch from DB
List<FriendWrapper> result = new ArrayList<>();
//TODO fill from database in result
return result;
}
#Override
protected void succeeded() {
getTableView().getItems().setAll(getValue());
}
}
You can launch this one as a Thread, for example:
new Thread(new LoadFriendsTask()).start()
For further reference:
JavaFX - Background Thread for SQL Query
How can I do asynchrous database in JavaFX
Multithreading in JavaFX

Use this...
Platform.runLater(new Runnable() {
#Override
public void run() {
}
});

Related

update marker position every x time in asynctask

I wanted to mock location of a marker on map. I have list of LatLng values store in ArrayList. I use this value to update on map every second. I need this function to works in AsyncTask so that my UI thread will still responsive.
Initially, I tried using Thread.sleep() but made application not responsive.
protected String doInBackground(Void... voids) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
for (int i = 0; i < waypoint.size(); i++) {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i));
try {
Thread.sleep(1000); // Thread sleep made application not responsive.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, 500);
return null;
}
I also tried using .postDelayed but the integer i needs to get declared final which is a problem because I need the integer to change value.
protected String doInBackground(Void... voids) {
for (int i = 0; i < waypoint.size(); i++) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i)); // Integer i needs to declare final.
}
}, 1000);
}
return null;
}
Is there any way to do this? Thank you.
The Thread.sleep() approach is OK if you can spare a worker thread. The problem in your code is that the thread you are pausing is the UI Thread, that's why your application freezes. You have to understand that what your doing there is just publishing a runnable to the UI Thread using the Handler construct, nothing more.
In your second approach, you can dump the Handler part and use publishProgress (called from the background) after you override onProgressUpdate (delivered in UI thread) in your AsyncTask based class. It does effectively the same but with less boilerplate. Take a look at https://developer.android.com/reference/android/os/AsyncTask for details.
Finally, to circumvent the final requirement in anonymous classes, you can declare a final array of one element and use position 0 to read/write the value. Hopefully, you won't need to do this too often.
The fastest (but not the most correct when working with MultiThreading) way is:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
}, 1000);
}
return null;
}
I don't know what was the Type of "waypoint" List, so I wrote "TYPE_OF_WAYPOINTS" as placeholder.
#emandt answer does not work but the idea he gave could work. So I tried and it is working flawlessly with some modified from his answer:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
});
try {
Thread.sleep(1000);
} catch (Exception e) {
// catch exception here
}
}
return null;
}
Firstly, I have change the .postDelayed to .post. Then, to delay the operation by one second, I have added Thread.sleep(1000) inside for (...) but outside new Handler(Looper.getMainLooper()).post(...));.
Now, the application could do the process in the background with user still be able to interact with the UI. Thanks.

CountDownLatch in Android locking thread

I've just started playing around with CountDownLatch in my Android app. Currently I am trying to make two Volley requests to my api, and wait until the data has been retrieved and stored before continuing with thread execution.
This is a sample of my code:
// new CountDownLatch for 2 requests
final CountDownLatch allDoneSignal = new CountDownLatch(2);
transactions.getResourcesForRealm(Contact.class, "", new ICallBack<Contact>() {
#Override
public void onSuccess(ArrayList<Contact> resources, String resourceId) {
transactions.createRealmObject(resources, Contact.class);
allDoneSignal.countDown();
}
#Override
public void onFail(ArrayList<Contact> resources) {
}
});
transactions.getResourcesForRealm(Meeting.class, "", new ICallBack<Meeting>() {
#Override
public void onSuccess(ArrayList<Meeting> resources, String resourceId) {
transactions.createRealmObject(resources, Meeting.class);
allDoneSignal.countDown();
}
#Override
public void onFail(ArrayList<Meeting> resources) {
}
});
try {
allDoneSignal.await();
// continue executing code
// ...
} catch (InterruptedException e) {
e.printStackTrace();
}
The issue is that it doesn't seem to "complete" the countdown and therefore freezes because the latch is never released. I have confirmed that the API requests are working and the onSuccess callback is hit successfully, but the thread hangs.
UPDATE
I've just noticed that with the CountDownLatch set to 0, it hits onSuccess, but when I set it to anything greater than 0, it freezes and onSuccess is never called. Seems like something's funky with the threading.
Your code is too error prone, you need to call countDown() in a finally block and call it also in onFail otherwise in case of failure your application will freeze for ever. So your code should rather be something like:
transactions.getResourcesForRealm(Contact.class, "", new ICallBack<Contact>() {
#Override
public void onSuccess(ArrayList<Contact> resources, String resourceId) {
try {
transactions.createRealmObject(resources, Contact.class);
} finally {
allDoneSignal.countDown();
}
}
#Override
public void onFail(ArrayList<Contact> resources) {
allDoneSignal.countDown();
}
});
transactions.getResourcesForRealm(Meeting.class, "", new ICallBack<Meeting>() {
#Override
public void onSuccess(ArrayList<Meeting> resources, String resourceId) {
try {
transactions.createRealmObject(resources, Meeting.class);
} finally {
allDoneSignal.countDown();
}
}
#Override
public void onFail(ArrayList<Meeting> resources) {
allDoneSignal.countDown();
}
});
Sorry for the late answer, but if it's still any help to anyone:
You need to do the ".await" in a separate thread because it blocks the current thread.
Example:
final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
new Thread(new Runnable() {
#Override
public void run() {
allDoneSignal.await();
mainThreadHandler.post(new Runnable() {
doSomethingWhenAllDone();
});
}
}).start()

Populate JList with threads

I want JList to be populated with multiple threads.
I tried this way but jlist is empty.
It would be good if jlist was updated on the fly
There are two threads, the other one loads in anouther direction
new Thread(new Runnable() {
#Override
public void run() {
for(i=0; i<cells.size()/2; i++){
System.out.println("thread");
try{
HtmlPage p = client.getPage("https://tbilisi.embassytools.com/en/slotsReserve?slot="+cells.get(i).getAttribute("data-slotid"));
pages.add(p);
if(!p.getUrl().toString().contains("slotsReserve"))
model.add(i,p.getUrl().toString());
}
catch (Exception e){
e.printStackTrace();
}
}
}
});
list1.setModel(model)
Thanks in advance
UPDATE*
So I fixed by using SwingWorker
Swing is a single threaded framework, that is, it is expected that all updates and modifications to the UI are done from within the context of the Event Dispatching Thread.
Equally, you should do nothing in the EDT that might block or otherwise prevent it from processing the Event Queue (like downloading content from the web).
This raise a conundrum. Can't update the UI outside the EDT, need to use some kind of background process to execute time consuming/blocking tasks...
So long as the order of items is unimportant, you would use multiple SwingWorkers in place o of the Threads, for example...
DefaultListModel model = new DefaultListModel();
/*...*/
LoadWorker worker = new LoadWorker(model);
worker.execute();
/*...*/
public class LoaderWorker extends SwingWorker<List<URL>, String> {
private DefaultListModel model;
public LoaderWorker(DefaultListModel model) {
this.model = model;
}
protected void process(List<String> pages) {
for (String page : pages) {
model.add(page);
}
}
protected List<URL> doInBackground() throws Exception {
List<URL> urls = new ArrayList<URL>(25);
for(i=0; i<cells.size()/2; i++){
try{
HtmlPage p = client.getPage("https://tbilisi.embassytools.com/en/slotsReserve?slot="+cells.get(i).getAttribute("data-slotid"));
pages.add(p);
if(!p.getUrl().toString().contains("slotsReserve")) {
publish(p.getUrl().toString());
urls.add(p.getUrl());
}
}
catch (Exception e){
e.printStackTrace();
}
}
return urls;
}
}
This allows you execute your blocking/long running in the backround (doInBackground) and publish the results of this method which are then processed within the context of the EDT...
See Concurrency in Swing for more details
Swing is not thread safe you should use SwingUtilities to run multiple threads updating swing.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
doWhateverYouWant();
}
});
read more

JTable not updating from a SwingWorker thread

I currently have a JTable that is populated with a series of data that forms the basis of a import screen. When I have finished selecting which updates I want or do not want, I press on the Apply button and the updates are applied successfully but the JTable does not fully update.
This is the code for the method that deals with applying the changes:
private void doProcessChanges() {
ChangeProcessor cp = new ChangeProcessor();
final List<Integer> rowsToRemove = new ArrayList<Integer>();
BeanTableModel<UpdateModel> model = (BeanTableModel<UpdateModel>) table.getModel();
for (int i=0; i<model.getRowCount(); i++) {
UpdateRow ur = mode.getObject(i);
if (ur.isAccepted() <> ChangeAcceptance.NO_ACTION) {
cp.processChange(ur);
rowsToRemove.add(i);
}
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
for (int row : rowsToRemove) {
model.removeObject(row);
model.fireTableDataChanged();
}
}
);
}
The method is called from within a SwingWorker thread as below:
SwingWorker<Object, Object> worker = new SwingWorker<Object, Object>() {
#Override
protected Object doInBackground() throws Exception {
doProcessChanges();
return null;
}
#Override
protected void done() {
try {
get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
I do not get any exceptions from executing this so I am I doing anything wrong?
Thanks in advance.
Your fragment shows incorrect synchronization. In particular, you access BeanTableModel, a subclass of AbstractTableModel, from the background thread. Instead, pass the List<Integer> rowsToRemove to your worker in its constructor.
Addendum: Instead of invokeLater(), you can update the TableModel in your implementation of process(), which executes on the EDT. Also, you shouldn't have to fireTableDataChanged(), which "Notifies all listeners that all cell values in the table's rows may have changed." The removeObject() implementation should fire the least pervasive event required to effect the change.

How to stack up incoming data

Each time a back-end message comes I add it to JList and JList is being refreshed using fireIntervalAdded. The problem is that in one second 20 messages may arrive and each one of them will call fireIntervalAdded. What I would like to do is to stack all messages in List and send one big stack of data to JList. My current solution does not seem to work, it always sends one message instead of one big stack:
private class StackingListener implements MessageListener {
private List<Message> messages = new LinkedList<Message> ();
private int waiting = 0;
#Override
public void messageReceived(MessageEvent event) {
stackData(event.getData());
}
private void stackData(Message data) {
messages.add(data);
if (waiting <= 0) {
waiting = 3;
new Thread(new Runnable() {
#Override
public void run() {
while(--waiting > 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
List<Message> list = new ArrayList<Message>(messages);
messages.clear();
logger.info("Adding list with size of " + list.size());
controller.getListModel().addFullElements(list);
}
}).run();
} else {
waiting = 3;
}
}
}
I think I'm doing something very wrong. The idea of this code is to stack up messages while Thread is sleeping. But seems like Thread.sleep stops everything, not only the current thread.
Thanks
You are using Thread.run() which just calls the run() method in the current thread. What you intended to use was Thread.start() creates a thread and call run() in that new thread.
However I wouldn't structure the code like this at all. I believe a simpler apporach is to use a queue.
class StackingListener implements MessageListener, Runnable {
private final BlockingQueue<Message> messages = new LinkedBlockingDeque<Message>();
private final ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); {
service.scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS);
}
#Override
public void messageReceived(MessageEvent event) {
messages.add(event.getData());
}
#Override
public void run() {
final List<Message> list = new ArrayList<Message>();
messages.drainTo(list);
logger.info("Adding list with size of " + list.size());
// add to the GUI component in a thread safe manner.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
controller.getListModel().addFullElements(list);
}
});
}
public void stop() {
service.shutdown();
}
}

Categories