How to update SWT GUI in asyncExec() call - java

In my SWT GUI, I would like to have a button that kicks off a job and while running that job, update a textbox that will show a log of the events of that job. However, my textbox does not update until the end of my asyncExec() call. In the example below, I would like for my textbox to be updated every second, but instead it gets all of the updates at once after 10 full seconds when it finishes executing.
Is there a way to achieve this?
private void UpdateUI()
{
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run()
{
StringBuilder sb = new StringBuilder();
for(int i=1; i<=10; i++)
{
sb.append("Running iteration " + i + "\n");
txtLogBox.setText(sb.toString());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}});
}

You're sleeping in the UI thread. You need to do your long-running work in a different thread and only post updates to the UI thread using asyncExec. For example:
new Thread(new Runnable() {
public void run()
{
StringBuilder sb = new StringBuilder();
for(int i=1; i<=10; i++)
{
sb.append("Running iteration " + i + "\n");
final String result = sb.toString();
Display.getDisplay().asyncExec(new Runnable() {
public void run()
{
txtLogBox.setText(result);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();

Related

Using Syncroniation wait/notify complete stops program from working Android

I am trying to stop the for loop and wait until the method has finished and continue once it has called onFinish. I was suggested to use either CyclicBarrier or syncronized wait/notify, but neither of them work.
When I run the method without the "stoppers", it always reaches to the onFinish, calling all 3 System.out.prints, but when I add either CyclicBarrier or syncronized it just does not start ticking. Meaning it only prints the first line countDownTimer first call and then stops and does nothing.
Just to make it shorter I have added both stoppers here to show how I did either of them, but I did use them seperately.
What can I do to make it "tick" ?
cyclicBarrier = new CyclicBarrier(2);
object = new Object();
for (int i = 0; i < sentenceList.size() - 1; i++) {
String currentLyricLine = sentenceList.get(i).content;
long diff = sentenceList.get(i+1).fromTime - sentenceList.get(i).fromTime;
int interval = (int) (diff / sentenceList.get(i).wordCount);
if(isFirstLine) {
startLyricCountDownTimer(diff, interval, currentLyricLine, coloredLyricsTextViewFirstLine);
isFirstLine = false;
} else {
startLyricCountDownTimer(diff, interval, currentLyricLine, coloredLyricsTextViewSecondLine);
isFirstLine = true;
}
//First tried with this
synchronized (object) {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Then tried with this
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
private void startLyricCountDownTimer(final long millisInFuture, final int countDownInterval, String lyrics, final ColoredLyricsTextView coloredLyricsText){
System.out.println("countDownTimer first call" );
coloredLyricsText.setText(lyrics);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
new CountDownTimer(millisInFuture,10) {
#Override
public void onTick(long millisUntilFinished) {
System.out.println("countDownTimer second call + " + millisUntilFinished);
//Do some stuff (irrelevant since it never gets here)
}
#Override
public void onFinish() {
System.out.println("countDownTimer last call" );
//First tried with this
synchronized (object) {
object.notify();
}
//Then tried with this
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}.start();
}
});
}
If i understand correctly then it was also mentioned that I run my loop on UI thread which is why everything stops. And well I do not wish to stop the UI thread, just to wait for one countDownTimer to finish, then start a new loop.

How to correctly block Eclipse job

I am using org.eclipse.core.runtime.jobs.JOB to execute backgrounds task that also gathers data from UI controls.
I want to "block" until job is finished (the trigger for the JOB is some ui button event)
Job job = new Job("Job") {
protected IStatus run(IProgressMonitor arg0) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println(i);
}
}
});
return Status.OK_STATUS;
}
};
job.schedule();
job.join(); //<-- Doesn't block!!!
if (job.getResult().isOK())
System.out.println("success"); //<-- Result is ok!!
else
System.out.println("failed");

Black view when starting new thread

In my android application I want an automatically refresh every 60 seconds. So I tried it like this:
public void refresh_check() {
Thread myThread = new Thread()
{
int counter = 0;
#Override
public void run() {
MyActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
while (counter < 60) {
try {
Thread.sleep(1000);
counter += 1;
System.out.println("Counter: " + counter);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
refresh();
}});
super.run();
}
};
myThread.start();
}
This works in the way that it prints the counter into logcat but in my Application I get a black view. refresh() is just a function with a http request, and this works alone, so the mistake has to be in the thread at any place :/ Can someone help?
You are not utilizing the Thread correctly. Running long tasks on the UI thread is just like not using a Thread at all. To accomplish what you need you should do it like this:
public void refresh_check() {
Thread myThread = new Thread()
{
int counter = 0;
#Override
public void run() {
while (counter < 60) {
try {
Thread.sleep(1000);
counter += 1;
System.out.println("Counter: " + counter); //I think this may cause exception, if it does try removing it
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
refresh(); // In refresh(), use TextView.post(runnable) to post update the TextView from outside the UI thread or use handlers
}});
super.run();
};
myThread.start();
}
Also, take a look at AsyncTask class, it enables you to run long tasks outside UI thread (doInBackground()) as well as update UI with the result from (onPostExecute())

java: Printing odd even numbers using 2 threads

I am trying to print odd and even numbers using 2 different threads alternately. I was able to achieve it using wait, notify and synchronize block but now i want to evaluate if we can achieve it without using wait, notify and synchronize.
Following is the code i have but its not working:
public class OddEvenUsingAtomic {
AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);
public static void main(String args[]) {
final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pc.chk.compareAndSet(true, false)) {
System.out.println("Odd: " + pc.nm.incrementAndGet());
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
if (pc.chk.compareAndSet(false, true)) {
System.out.println("Even: " + pc.nm.incrementAndGet());
}
}
}
}).start();
}
}
Any ideas?
I created another version after suggestions from Bruno which seems to be working better:
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class OddEvenUsingAtomic {
AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);
public static void main(String args[]) {
final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pc.chk.get() == Boolean.TRUE) {
System.out.println("Odd: " + pc.nm.incrementAndGet());
pc.chk.compareAndSet(true, false);
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
if (pc.chk.get() == Boolean.FALSE) {
System.out.println("Even: " + pc.nm.incrementAndGet());
pc.chk.compareAndSet(false, true);
}
}
}
}).start();
}
}
The code is not correctly synchronized, that's the problem.
The following execution order is allowed in your code:
First thread sees chk == true, sets it to false and enters the if block.
Second thread sees chk == false, sets it to true and enters the if block.
Now, you have 2 threads both inside their if blocks, getting ready to:
incrementAndGet() the number
Print it.
Therefore, you have absolutely no control on what is going to happen.
You can have any of the threads call incrementAndGet(), therefore you can have thread "Odd" printing, first, an odd number, and later, an even number.
You can have the first thread print the number, loop, see that the condition is satisfied again (since the second thread has set chk to true again, print, all of this before the second thread had the chance to print).
As you can see, to achieve the result you want, you must have the following operations done atomically:
compareAndSet() the boolean
incrementAndGet() the number
print it
If the 3 operations are not atomic, then you can have the threads being scheduled to run the operations in any possible order, you have no control on the output. The easiest way to achieve this is to use a synchronized block:
public static void main(final String... args) {
final Object o = new Object();
// ... thread 1 ...
synchronized(o) {
if (boolean is in the expected state) { change boolean, get number, increment, print }
}
// ... thread 2 ...
synchronized(o) {
if (boolean is in the expected state) { change boolean, get number, increment, print }
}
}
Here are two threads printing odds and evens with no wait, notify, or synchronized (at least not in the code you can see):
import java.util.concurrent.*;
public class ThreadSignaling {
public static void main(String[] args) {
BlockingQueue<Integer> evens = new LinkedBlockingQueue<>();
BlockingQueue<Integer> odds = new LinkedBlockingQueue<>();
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(() -> takeAndOfferNext(evens, odds));
executorService.submit(() -> takeAndOfferNext(odds, evens));
evens.offer(0);
}
private static void takeAndOfferNext(BlockingQueue<Integer> takeFrom,
BlockingQueue<Integer> offerTo) {
while (true) {
try {
int i = takeFrom.take();
System.out.println(i);
offerTo.offer(i + 1);
} catch (InterruptedException e) {
throw new IllegalStateException("Unexpected interrupt", e);
}
}
}
}
class MultiThreading {
Integer counter = 0;
Thread even;
Thread odd;
boolean flagEven = true;
boolean flagOdd;
class ThreadEven implements Runnable {
#Override
public void run() {
try {
while (counter < 100) {
if (flagEven) {
System.out.println(counter);
counter++;
flagEven = false;
flagOdd = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ThreadOdd implements Runnable {
#Override
public void run() {
try {
synchronized (even) {
while (counter < 100) {
if (flagOdd) {
System.out.println(counter);
counter++;
flagOdd = false;
flagEven = true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void start() {
even = new Thread(new ThreadEven());
odd = new Thread(new ThreadOdd());
even.start();
odd.start();
}
}
}
call in the main method
new MultiThreading().start();

display.async and smooth transitions

I have got my custom widget that changes background when hover. It is working nice but I would like to have smooth transition between no background and hover background. It will work with GC.setAlpha(), but:
Display.getDefault().asyncExec(new Runnable() {
public void run() {
for (int i=0;i<255;i++) {
setBG(BGHelper(imgHover,i)); //i - alpha
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
This code wait until i == 255, but it doesn't display a smooth transition. Why?
This can not work, because as long as you are in your Code SWT will not repaint or change the component.
You should do the work in a separate Thread and call Display.asyncExec for every change.
for (int i = 0; i < 255; i++) {
final int x = i;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
setBG(BGHelper(imgHover,x)); //x - alpha
}
});
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Categories