This question already has an answer here:
nested postDelayed / Runnable / Handler Android
(1 answer)
Closed 4 years ago.
Basically , i have 5 Runnables for each user.
Inside each Runnable, There must be waiting for a variable to change until it continues. I'll be using either a Semaphore or a CountDownLatch.
So inside each Runnable there is a runnable for waiting.
Here's an example. r1 is a runnable supposed to be user so never ending.
final Handler handler = new Handler();
Runnable r1 = new Runnable() {
#Override public void run() {
// here must be another runnable for waiting
Runnable r2 = new Runnable() {
#Override public void run() {
if (condition) {
latch.countDown();
// ending the runnable
handler.removeCallbacks(r2);
} else {
// keep waiting
handler.postDelayed(r2, 1000);
}
}
}
latch.await();
// restarting the runnable
handler.postDelayed(r1, 1000);
}
}
The problem when using latch.await() is that is running in main thread so blocking the UI.
Any idea how to starts those runnable in different threads?
What i wanted to do is a non stop running Thread that somewhere needs to wait a variable to change so it continues other instructions. Somewhere in the UI when a button is clicked ,a semaphore gets incremented. And in the thread it waits until it is available. Here's the solution i made
Semaphore sem = new Semaphore(0,true);
//somewhere in UI sem.release();
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
semaphore.acquire();
// when updating the UI is needed
runOnUiThread(new Runnable() {
#Override
public void run() {
// work
}
});
}
} catch (InterruptedException e) {
}
}
}
Related
In a run method of a TimerTask object, How can I submit the timerTask itself to another Timer.
When the timerTask is running, I should do a judge and decide whether it can do some work. If it not meet the condition, I should cancel it and put it to another Timer.
Code of my TimerTask is like this:
#Override
public void run() {
try {
if (flag) {
// do something
} else {
new Timer().schedule(this, 1000 * 60);
}
} catch (Exception e) {
e.printStackTrace();
}
Will it work?
You should only use one Timer and then monitor the condition from external, for example from a Thread, a Runnable or another Timer. Then stop, cancel, re-assign, start the timer as necessary from your external monitor.
Here's a TimerTask:
public class OurTask extends TimerTask {
#Override
public void run() {
// Do something
}
}
And here's the monitor:
public Monitor implements Runnable() {
private Timer mTimerToMonitor;
public Monitor(Timer timerToMonitor) {
this.mTimerToMonitor = timerToMonitor;
}
#Override
public void run() {
while (true) {
if (!flag) {
// Cancel the timer and start a new
this.mTimerToMonitor.cancel();
this.mTimerToMonitor = new Timer();
this.mTimerToMonitor.schedule(...);
}
// Wait a second
Thread.sleep(1000);
}
}
}
Note that in practice your Monitor should also be able to get canceled from outside, currently it runs infinitely.
And this is how you could call it:
Timer timer = new Timer();
timer.schedule(new OurTask(), ...);
Thread monitorThread = new Thread(new Monitor(timer));
monitorThread.start();
Also note that instead of using Runnable, Timer and Thread it could be worth taking a look into the new Java 8 stuff, especially the interface Future and classes implementing it.
my program's UI freezes for some time after pressing a JButton. I discovered that a cause of this is a Semaphore clogging the Swing thread. This is the method containing the acquire() call on the Semaphore:
private void fetch(int numThreads) {
//some code here
sem = new Semaphore(numThreads);
for (int i = 0; i < model.getRowCount(); i++){
try {
sem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
//some code here
}
And here is the only method that makes a call to fetch()
concFetchButt.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
switchButtonStates(false);
}
});
fetch(Integer.parseInt(threadsNumField.getText()));
}
As I understand, this code ends up running fetch() on the Swing thread, though, supposedly it has nothing to do with Swing.
I guess, my question is this: How do I run a method called from 'ActionPerformed()' of Swing on the main thread of the program instead of the Swing thread?
No need to specifically run that on the "main" thread. Simply run it on any other thread but the Swing UI thread.
The most simple solution to get there:
add an ExecutorService to your class
put that code fetch(Integer.parseInt(threadsNumField.getText())); into a Runnable object
Submit that Runnable to the ExecutorService
Along the lines of:
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
fetch(Integer.parseInt(threadsNumField.getText()));
}
});
I'm trying to make an JavaFX application that tracks the movement of my mouse for this im using this code in the controller class:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}).start();
But it couses my application to lag big time.
How should i fix this lag problem?
Thanks i fixed it:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
}
});
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
What you doing is letting Javafx Application thread Thread.sleep(1000); <-wait
Any long term action you shoud put OUT of JFX-AT. And only update your ui components on it.
new Thread(()->{
while(Main.running){
Platform.runLater(()->{
//updateui component
//this is updating on FXAT
});
Thread.sleep(time)//This way you dont let JFXAT wait
}
}).start();
//Not sure if formatted and curly braces correctly.Bud you hopefully understand.Make sure you know which thread you let wait.Otherwise you wont be able to recieve events from paused jfxat.
You should put your Thread.sleep() call in your while loop and not in your Runnable, otherwise the loop keeps posting a lot of runLater tasks and those tasks stops the event thread for 1000ms after updating your mouse position
You call Thread.sleep(long) inside a Runnable that will be executed on the UI thread. If the thread is sleeping, it can't do anything else but sleep there. If you want your label to update every 1000 milliseconds, you can use the java.util.Timer class to make that happen.
I want to setText from within a Thread.
This is my code of the Thread:
private class GenerateThread implements Runnable {
public void run(){
// generate the first music
music = generate(prevmusic, prevmusic.length);
prevmusic = music;
// write the midi
writeMidi(music, song);
textOut.setText("Initialising...");
});
}
}
in my main code, I use
Thread t = new Thread(new GenerateThread());
t.start();
It does not allow me to setText from within the thread.
Following some posts on internet, I have tried using a handler, but that gave me errors, I think I am double defining Runnable this way.
Handler handler (before main)
private class GenerateThread implements Runnable {
public void run(){
handler.post(new Runnable() {
// generate the first music
music = generate(prevmusic, prevmusic.length);
prevmusic = music;
// write the midi
writeMidi(music, song);
textOut.setText("Initialising...");
});
}
}
How can I setText from within the Thread? Thanks!
besides runOnUiThread there is also View#post(Runnable) which I would prefer here because you don't need ugly looking references to the outer Activity (MyActivity.this.runOnUiThread()).
private class GenerateRunnable implements Runnable {
public void run() {
// this code is executed in a background thread.
// generate the first music
music = generate(prevmusic, prevmusic.length);
prevmusic = music;
// write the midi
writeMidi(music, song);
textOut.post(new Runnable() {
public void run() {
// this code is executed on the UI thread.
textOut.setText("Initialising...");
}
});
}
}
#Override
protected void onResume() {
super.onResume();
new Thread(new GenerateRunnable()).start();
}
Also don't confuse Runnable and Thread. A Runnable is just an ordinary class with a run() method. It can be and often is executed on a new Thread. If you want you can also make GenerateThread a real Thread like so:
private class GenerateThread extends Thread {
#Override
public void run() {
// code here.
}
}
// start somewhere
new GenerateThread().start();
And besides using classic Thread you could also think about using AsyncTask since that is made exactly for tasks that do something long running and need to update the UI afterwards or when there is progress.
One can only update the UI from the UI thread. runOnUiThread will allow you to run an action on the UI thread the next time it executes. You can do something like:
runOnUiThread(new Runnable() {
public void run() {
textOut.setText("Initialising...");
}
});
EDIT:
private class GenerateThread implements Runnable {
public void run(){
// generate the first music
music = generate(prevmusic, prevmusic.length);
prevmusic = music;
// write the midi
writeMidi(music, song);
// Update the UI
MyActivity.this.runOnUiThread(new Runnable() {
public void run() {
textOut.setText("Initialising...");
}
});
}
}
I would like to get a recurring call back to invalidate a view. I am sure there is a neat way to do this. I am currently doing this and would like a neater / better solution if possible?
new Thread()
{
#Override
public void run()
{
while (!Thread.currentThread().isInterrupted())
{
handler.post(new Runnable()
{
public void run()
{
BannerButton.this.invalidate();
}
});
try
{
Thread.sleep(50); // yields 20 fps
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
}.start();
For a single shot timer on the UI thread, I do this: (But I cant find a way to do this with repeats)
(new Handler()).postDelayed(new Runnable()
{
#Override
public void run()
{
// Do stuff
}
}, SPLASH_SHOW_TIME);
Timer looked good, but it calls on a background thread.
Thanks.
Your second try using Handler is already correct. Just store the Handler and the Runnable in a field, and then inside the run() method (possibly at the end), call again
handler.postDelayed(runnable, 1000);
Look at the View.postInvalidate() method. This is different from invalidate() as you can do it from any Thread you want. It just posts an invalidate() message in the UI thread Looper
Concerning your second question simply post with some delay the same Runnable at the end of the Runnable in your Handler