How does Platform.runLater() function? - java

I have a simple app which updates the data in the background and while it updates, it disables all the other buttons and enables a TextArea to show the progress.
Steps:
Disable all the other buttons in the mainUI (Button name: plotButton)
Enable a TextArea showing that the updating has started (TextArea name: infoLogTextArea)
Then only start the update method (update() throws Exceptions).
Here is the code:
#FXML
public void handleUpdateButton() {
infoLogTextArea.setVisible(true);
infoLogTextArea.appendText("Please wait while downloading data from internet.....\n");
plotButton.setDisable(true);
updateButton.setDisable(true);
if(c!=null) {
Runnable task = new Runnable() {
#Override
public void run() {
// Thread.sleep(10000); -> sleep for 10secs
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
c.updateData();
infoLogTextArea.appendText(c.getErrorLog().toString());
plotLabel.setText(c.getCityData().size()+" cities found and updated from internet");
infoLogTextArea.appendText("Successfully updated the data from Internet\n");
}catch (IOException e) {
infoLogTextArea.setText("Couldnot update the data from web: "+e.getMessage()+"\n");
}
finally {
plotButton.setDisable(false);
updateButton.setDisable(false);
}
}
});
}
};
new Thread(task).start();
}else {
System.out.println("c not initialized");
}
}
Now the code works well but sometimes steps 1 and 2 are not executed and it starts step 3 (updating) which can freeze the program.
If I put Thread.sleep(10 secs) in between step 2 and 3 then it works completely fine. (it is commented in the code)
But can anybody explain what is going on behind the scenes and why Platform.runLater() doesn't work all the time?

A JavaFX application runs on the Application thread, which handles all the UI elements. This means that if you click Button A and clicking that button starts method A that takes 5 seconds to complete, and then one second after clicking that button, you try to click Button B which starts method B, method B won't start until method A finishes. Or possibly Button B won't even work until method A finishes, I'm a little fuzzy on the detail there.
A good way to stop your application from freezing is to use Threads. To fix the above scenario, clicking Button A will start method A that starts a new Thread. Then the Thread can take as long as it wants to complete without locking up the UI and preventing you from clicking Button B.
Now, say something in method A needed to be on the application thread, for example, it updated a UI component, like a Label or a TextField. Then inside your Thread in Method A you would need to put the part that affects the UI into a Platform.runLater(), so that it will run on the Application Thread with the rest of the UI.
What this means for your example is that you have two options.
1. Don't use threads at all, since you don't want the user to be interacting with the UI while the updates are happening anyway.
2. move c.updateData() out of the Platform.runLater() like this:
Runnable task = new Runnable() {
#Override
public void run() {
c.updateData();
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
infoLogTextArea.appendText(c.getErrorLog().toString());
plotLabel.setText(c.getCityData().size()+" cities found and updated from internet");
infoLogTextArea.appendText("Successfully updated the data from Internet\n");
}catch (IOException e) {
infoLogTextArea.setText("Couldnot update the data from web: "+e.getMessage()+"\n");
}
finally {
plotButton.setDisable(false);
updateButton.setDisable(false);
}
}
});
}
};
Either one of those will work, but what you're doing right now is you're on the application thread, and then you start another thread whose only purpose is to run something on the application thread.

The documentation of the Platform class explain everything very well :
public static void runLater(Runnable runnable)
Run the specified Runnable on the JavaFX Application Thread at some
unspecified time in the future. This method, which may be called from
any thread, will post the Runnable to an event queue and then return
immediately to the caller. The Runnables are executed in the order
they are posted. A runnable passed into the runLater method will be
executed before any Runnable passed into a subsequent call to
runLater. If this method is called after the JavaFX runtime has been
shutdown, the call will be ignored: the Runnable will not be executed
and no exception will be thrown. NOTE: applications should avoid
flooding JavaFX with too many pending Runnables. Otherwise, the
application may become unresponsive. Applications are encouraged to
batch up multiple operations into fewer runLater calls. Additionally,
long-running operations should be done on a background thread where
possible, freeing up the JavaFX Application Thread for GUI operations.
This method must not be called before the FX runtime has been
initialized. For standard JavaFX applications that extend Application,
and use either the Java launcher or one of the launch methods in the
Application class to launch the application, the FX runtime is
initialized by the launcher before the Application class is loaded.
So use the runLater to only update any UI elements on a non JavaFX thread and leave any heavy job to sit on the background thread.

Related

Why android room inserts an object at the end of the asynctask generating it (the object)?

Summary
Room immediately inserts entities generated through UI, but delays those sent by an asynctask until the (far) end of the generating asynctask : the entity objects received are usable and displayed on UI, but without any id from database, hampering any other operation relying on id.
The insert operation happens only when the generating asynctask is properly stopped: Why? And how to solve this?
More context
The generating asynctask
We use an asynctask to monitor a socket and send back some events (as Room entity) to the application repository (as intended by android architecture components). This asynctask basically runs continuously in background (with some sleep regularly set) and is only stopped a while before the end of use of the application (if done right). So far it hasn't caused any issue for us to deviate so much from the original concept of short-lived asynctask.
I am pretty much aware we could improve the design, but this is another subject/question/time-hole ;-).
Room insert operation
Insertion happens through a dedicated asynctask, where the returned id of the entry in database is affected back to the entity just inserted (see code below). This is logged and entities from UI are persisted "immediately", they get back their ID and all is well. The asynctask-generated entities, well they wait for their "parent" task to stop and are then all inserted.
Entity composition
At first, the entity was generated inside the asynctask and sent through progress message. Then the construction of the object was moved outside of the asynctask and at the same level of the UI event construction, yet same behavior.
These events are some longs (timestamps) and several strings.
From the generating asynctask all starts from here:
#Override
protected void onProgressUpdate(OnProgressObject... values) {
OnProgressObject onProgressObject = values[0];
if (onProgressObject instanceof OnProgressEvent) {
eventRecipient.sendAutoEvent(((OnProgressEvent) onProgressObject).autoEvent);
}
}
The eventRecipient is the EventsRepository:
public void sendAutoEvent(AutoEvent autoEvent) {
Log.d(LOG_TAG, "got an autoevent to treat...");
EventModel newEvent = EventModel.fromCub(
autoEvent.cubTimeStamp,
autoEvent.description,
autoEvent.eventType
);
addEvent(newEvent);
}
public void addEvent(EventModel event) {
new insertEventAsyncTask(event).execute(event);
// other operations using flawlessly the "event"...
}
private class insertEventAsyncTask extends AsyncTask<EventModel, Void, Long> {
private EventModel eventModel;
public insertEventAsyncTask(EventModel eventModel) {
this.eventModel = eventModel;
}
#Override
protected Long doInBackground(EventModel... eventModels) {
// inserting the event "only"
return eventDao.insert(eventModels[0]);
}
#Override
protected void onPostExecute(Long eventId) {
super.onPostExecute(eventId);
// inserting all the medias associated to this event
// only one media is expected this way though.
eventModel.id = eventId;
Log.d(LOG_TAG, "event inserted in DB, got id : " + eventId);
}
}
I am pretty much aware we could improve the design, but this is another subject/question/time-hole
Since I suspect that it is the cause of your current problem, perhaps you should not dismiss this.
My interpretation of your problem is: you have an outer AsyncTask (the one with the onPublishProgress() method shown in the first code listing). You are executing that with execute(). Inside of that outer AsyncTask you have an inner AsyncTask (the one from your repository). You are executing that with execute(). And, your complaint is that the inner AsyncTask does not run until the outer AsyncTask completes.
If so, your problem is that execute() is single-threaded, and you are tying up that thread by having an AsyncTask run indefinitely. Until your outer AsyncTask completes its background work and returns from doInBackground(), the inner AsyncTask is blocked.
The "can we keep using hacks?" solution is to continue using AsyncTask but switch to executeOnExecutor() instead of execute(), supplying a thread pool to use. AsyncTask.THREAD_POOL_EXECUTOR would be a candidate.
The "OK, can we clean this up a little bit?" solution is to replace both AsyncTask instances with either simple Thread objects or the direct use of some multi-thread thread pool (see Executors). AsyncTask is obsolete, but to the extent that it is useful, only use it when you need to do work on the main application thread (onPostExecute()) after completing the background work (doInBackground()). Neither of your AsyncTask implementations need to be doing work on the main application thread after the background work is complete, so you do not need an AsyncTask for either of them. So, for example, your run-forever thread could be a Thread, while you use a thread pool inside of your repository for your DAO calls.
(the "hey, can we get modern on our threading, to go along with our use of Architecture Components?" solution is to switch to RxJava or Kotlin coroutines, in conjunction with LiveData — this is much more work, but they each have their own merits over manual thread management)
Why ?
Basically, it was written in the AsyncTask documentation : all asynctasks are executed serially on a unique background thread.
My code, even without nested asynctask, was blocking this thread with an almost never-ending task, delaying all database operations until its completion (or app crash, hence some data loss).
A quick solution : moving an AsyncTask to a Thread
Other alternatives were nicely listed by (CommonsWare)[https://stackoverflow.com/a/56925864/9138818], here are the steps I followed that solved this issue.
The main difficulty was to redirect code that was executed on UI thread (onPreExecute, onProgressUpdate, onPostExecute) through a Handler associated to the main thread.
First step was get a reference to a handler :
// Inside Runnable task's constructor :
// get the handler of the main thread (UI), needed for sending back data.
this.uiHandler = new Handler(Looper.getMainLooper());
Then, the "doInBackground" is refactored to fit a Runnable main method signature :
// previously "public String doInBackground()"
// returned value handled through publishProgress.
#Override
public void run() {
// recommended by Android Thread documentation
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// code previously in doInBackground
Now, code in the onProgressUpdate (that was called by publishProgress inside doInBackground method) was moved into a Runnable posted on the UI thread handler :
// asynctask method onProgressUpdate was renamed publishProgress =>
// doInBackground's body is almost untouched.
private void publishProgress(final OnProgressObject... values) {
uiHandler.post(new Runnable() {
#Override
public void run() {
// move here code previously in the AsyncTask's publishProgress()
}
});
}
At last, I had to change the way the task was created, runned and stopped by using Thread.interrupted instead of isCancelled and by creating the Runnable task before the thread :
public void startCUBMonitoring() {
if (autoEventThread == null) {
Log.d(LOG_TAG, "startCUBMonitoring");
addUIEvent("CUB MONITORING STARTED", "CUB_connexion");
SessionRepository sessionRepository =
ElabsheetApplication.getInstance().getSessionRepository();
// Creation of the task
AutoEventTask autoEventTask = new AutoEventTask(
this,
sessionRepository,
sessionRepository.getCUBConfig()
);
autoEventThread = new Thread(autoEventTask);
autoEventThread.start();
}
}
public void stopCUBMonitoring() {
if (autoEventThread != null) {
Log.d(LOG_TAG, "stopCUBMonitoring");
addUIEvent("CUB MONITORING STOPPED", "CUB_connexion");
autoEventThread.interrupt();
autoEventThread = null;
}
}
Hoped it could help...

Display.getDefault.syncExec() not running correctly in headless mode

I'm running my application in headless mode and for some execution i need to display a dialog in between for some specified time.
Code Sample
Display.getDefault().syncExec(new Runnable() {
#Override
public void run() {
//Jface Dialog code
RuntimePauseDialog dlg = new RuntimePauseDialog();
dialogResult = dlg.open();
}
});
The above code will be called multiple times and for the first time the Dialog appears. From 2nd time onwards the dialog doesn't show up. Moreover run() will not be executed at all and freezes. Inside syncExec() there is a Runnable lock which gets initialized and calls wait(), which waits forever (Application freezes)
I think this has something to do with Threads.
Note : The same code displays the dialog (multiple times) correctly when run from UI mode. The problem is only in headless mode.
Tried this suggestion from Stackoverflow, but since i'm running in headless mode, there will be no Workbench created and cannot use that.
syncExec (and asyncExec) relies on there being a main Display.readAndDispatch loop running in the UI thread. In headless mode this is not the case so this is simply not going to work at all.

Calling thread repeatedly causing Ui hang in android

I am developing a Bluetooth application.In that I have 1 button, on click of the button I am starting a thread.Inside the thread, I am discovering and connecting ble devices.Repeated click of the button causing the UI to hang.
Code I am using to create the thread is:
new Thread(new Runnable() {
#Override
public void run() {
//do bluetooth stuffs
}
}).start();
I am not stopping this thread anywhere.
I don't know what is causing the UI to hang please help me.
Do you mean that if you keep smashing the button repeatedly (without waiting for the task to finish), then the ui lags? Or when you press the button, wait a bit, then press again.
If it's the first case (where you're mashing the button in quick succession), try this: If you set some boolean flag when you first start the process, then each time you press the button check if that flag is set to true, and only execute the search if the flag is false. Not sure if this is your issue but it's worth a shot?
For the Android, you can use handler instead thread or handle your thread using handler is a better way, for example, you can use like
new Handler().post(new Runnable() {
#Override
public void run() {
}
});
if you want to use the main thread then use like.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
}
});
for information, you can refer this link
difference between Thread and Handler
I would advise you to use a thread pool instead. Resources are limited.I didn't understand why are you creating a new thread for every button press. a bunch of threads banging for a resource might freeze Your app, or there could be implementation related issues like a deadlock, thread contention, or thread starvation which will definately prompts to freeze your application.

How to wake thread by condition

I have an activity running, of course, on UI thread and there is another thread running in background and communicating with activity using Handler post method(through looper).
When screen is turned of or application is hidden it continues to work.
So I need to stop this thread in onPause method and wake it up in onResume mehtod.
In my thread I have condition to pause it or to stop.
How to can I put thread to sleep in onPause method. And wake it up after activity is again in foreground.
I can do it with one object using monitor calling wait method and than notify on this object.
But is it good approach ? Or there is another way to do this elegantly.
Sounds like a good place to use a turnstile. Initialize a Semaphore with one permit:
Semaphore turnstile = new Semaphore(1);
Make your background activity periodically pass through the turnstile like so:
turnstile.acquire();
turnstile.release();
When the foreground thread wants the background thread to pause at the turnstile, it can lock the turnstile:
turnstile.acquire();
And when the foreground thread wants that background thread to start working again, it can unlock the turnstile():
turnstile.release();
Good software engineering practice would be to wrap the whole thing up in a Turnstile class with appropriately named methods for the foreground and background threads to call. I'll leave that as an exercise for the reader.
Android suggests using services for long term background tasks, but if you're just opening a new thread that is tied to your Android lifecycle, I don't think it would be bad to use a monitor and call wait/notify. Can you be more specific with what you are doing?
This is an overview of how I would stop and resume a stopped thread. (You may want to implement runnable in yours)
class ThreadDemo extends Thread {
private Object monitor; //This is the monitor
private boolean keepRunning = true;
private Thread t;
ThreadDemo(){
System.out.println("Creating thread");
}
public void callinOnResume(){
synchronized(monitor){
monitor.notify();
}
}
public void callinOnPause(){
try {
synchronized(monitor){
System.out.println(threadName + "Waiting");
monitor.wait();
}
} catch (InterruptedException e) {
System.out.println("Thread interrupted " + e.toString());
}
}
public void run() {
System.out.println("Starting to loop.");
while (keepRunning) {
//stuff
}
System.out.println("Done looping.");
}
public void start ()
{
System.out.println("Starting " + threadName );
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
It is a bad practice to stop/resume a thread outside that thread. The thread must decide itself when to run and when to stop. As a result, the background thread should check periodically if its work is still needed, and the client (foreground) thread should issue some signals about that.
One way to issue signals is to form that signals as jobs of type Runnable and then execute them on a thread pool. So when the activity sleeps, it just does not issue signals.
The main problem when a background thread wants to update the UI is that the target Activity can be closed (or in the process of recreation) and the updating task fails. The AcyncTask class does not solve this problem. A correct solution is published at my Github workspace. But before to use this or another solution, think twice if you really need a background thread. The best way is not to use background thread at all, making all UI updates directly on the UI thread. Of course, if updates are taken from the network, then a background thread must be used.

Action in the concurrent thread is not executed when main thread is waiting

I have an application which use temporary tables (existed in the scope of user session) and complex data processing.
For debug purposes I need to execute queries to this temporary tables during the application processing.
I added some additional logic as aspects (AspectJ) and run my application as load-time weaving application in Eclipse (using AJDT/ JDT weaving plugin).
I do the following: after getting new connection I create another thread with gui and pass the connection to it (would be described later).
After each query the main application thread waiting for the message from gui thread to continue the work (that gives me an opportunity to make queries and see intermediate results in temporary tables). Messaging is implemented using BlockingQueue.
In the GUI I have a frame with text area for query and two buttons "Run query" and "Release main thread".
I wanted that pressing the "Run query" button will execute the query and show the results on the frame. And pressing the button "Release main thread" will send the message to the main thread to continue the work.
The problem is when the main thread is waiting for blockingQueue.take(), pressing the button "Run query" causes the frame to freeze and do nothing (it looks like gui becomes unresponsive).
When the main thread is waiting for blockingQueue.take(), "Release main thread" forks fine (but not after "Run query" pressing).
When the main thread is running (I put plenty of objects in the queue), "Run query" button works normally and I can see query results.
At first I've tried manipulations with EDT and events dispatching, but nothing has helped me. Have you any ideas of the problem?
//aspect on 'newConnection' pointcut
after() returning (final Connection connection): newConnection() {
gUI = new Runnable() {
public void run() {
new GuiView(blockingQueue, connection);
}
};
SwingUtilities.invokeLater(gUI);
}
//GuiView code extract for button with query data retrieval action
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
try {
ResultSet rs = ConnectionManipulator.executeStatement(
queryTextAreaG.getText()
);
///....result parsing logic
} catch (SQLException e1) {
JOptionPane.showMessageDialog(null, "Exception!");
} finally {
}
//....result out logic
}
});
GUIs usually run in the main thread (not only on Java), so if you let your main thread block, you block your GUI as well and it freezes.
EDIT
I think you got SwingUtilities.invokeLater wrong: it is being used to execute part of the code in the main event loop thread, so usually is being called from the background thread, not the other way round. Now it looks like the query were being executed in the event loop thread thus blocking GUI.
Let the query be executed in a normal thread and when it is ready call the mainthread callback using SwingUtilities.invokeLater.
Sorry, for trouble. The problem was in the incorrect pointcut description (not attached to the code above).
I had this the pointcut around:
PreparedStatement around(): prepareStatement() {
if (gUI != null) {
try {
blockingQueue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
}
}
return proceed();
But ConnectionManipulator.executeStatement uses prepareStatement() also .
So it executes blockingQueue.take(), which causes the GUI event thread to stop.
I`ve corrected the pointcut desription and the problem gone away.
Thank you all.

Categories