Hi Im trying to implement an exercise execution list where each exercise should change background color representing that thats the current exercise running every T time for each exercise. I wanted to know how to implement the action of waiting T time until the exercise finish to highlight the next one.
I have something like this, but blocking the thread is not doing the trick.
ArrayList<ExerciseData> exercises;
ExerciseData ex;
int curr = 0;
int cycleSize = warmUpAdapter.getItemCount();
exercises = (ArrayList<ExerciseData>) warmUpAdapter.getExerciseList();
while( curr < cycleSize ){
ex = exercises.get(curr);
ex.setRunning(true);
warmUpAdapter.notifyItemChanged(curr);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ex.setRunning(false);
warmUpAdapter.notifyItemChanged(curr);
curr++;
}
Try to use postDelayed method of Handler:
private static Handler handler = new Handler();
private void doExercise(final int curr){
ArrayList<ExerciseData> exercises = (ArrayList<ExerciseData>) warmUpAdapter.getExerciseList();
if (curr >= exercises.size()){
System.out.println("Finished");
return;
}
final ExerciseData ex = exercises.get(curr);
ex.setRunning(true);
System.out.println("Running exercise " + curr);
warmUpAdapter.notifyItemChanged(curr);
handler.postDelayed(new Runnable() {
#Override
public void run() {
ex.setRunning(false);
warmUpAdapter.notifyItemChanged(curr);
doExercise(curr + 1);
}
}, 1000);
}
... call later to start exercises:
doExercise(0);
Related
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.
I have this task run in a thread. The problem is that it freezes the UI every time it is executed. The freeze is longer when the internet is slow. How can I prevent the UI from freezing even if it is still gathering data from the url?
Task<Void> task = new Task<Void>(){
#Override
public Void call() throws Exception {
while (true) {
Platform.runLater(new Runnable() {
#Override
public void run(){
String json = null;
try {
psname = null;
PumpSites n = table.getSelectionModel().getSelectedItem();
psname = n.getPs();
if(psname == "Cubacub")
json = readUrl(""); //read json from thingspeak.com webpage
else if(psname == "Canduman")
json = readUrl("");
} catch (InterruptedIOException iioe)
{
btn1.setTextFill(Color.RED);
btn2.setTextFill(Color.RED);
btn3.setTextFill(Color.RED);
btn4.setTextFill(Color.RED);
btn5.setTextFill(Color.RED);
btn1.setText("NULL");
btn2.setText("NULL");
btn3.setText("NULL");
btn4.setText("NULL");
btn5.setText("NULL");
}
catch (IOException ioe)
{
btn1.setTextFill(Color.RED);
btn2.setTextFill(Color.RED);
btn3.setTextFill(Color.RED);
btn4.setTextFill(Color.RED);
btn5.setTextFill(Color.RED);
btn1.setText("NULL");
btn2.setText("NULL");
btn3.setText("NULL");
btn4.setText("NULL");
btn5.setText("NULL");
}
catch (Exception e1) {
btn1.setTextFill(Color.RED);
btn2.setTextFill(Color.RED);
btn3.setTextFill(Color.RED);
btn4.setTextFill(Color.RED);
btn5.setTextFill(Color.RED);
btn1.setText("NULL");
btn2.setText("NULL");
btn3.setText("NULL");
btn4.setText("NULL");
btn5.setText("NULL");
}
Gson gson = new Gson();
Page page = gson.fromJson(json, Page.class);
for (Item item : page.feeds)
{
det2 = 1;
btn1.setText(item.field1);
btn2.setText(item.field2);
btn3.setText(item.field3);
btn4.setText(item.field4);
btn5.setText(item.field5);
f2 = Float.parseFloat(item.field2);
f3 = Float.parseFloat(item.field3);
//float f5 = Float.parseFloat(item.field5);
if (f2 <= 10.0)
{
btn1.setTextFill(Color.RED);
btn2.setTextFill(Color.RED);
}
else
{
btn1.setTextFill(Color.BLUE);
btn2.setTextFill(Color.BLUE);
}
if (f3 < 0.9 || f3 > 1.2)
{
btn3.setTextFill(Color.RED);
}
else
{
btn3.setTextFill(Color.BLUE);
}
/*if (f5 > 5.0)
{
btn5.setTextFill(Color.RED);
}
else
{
btn5.setTextFill(Color.BLUE);
}*/
btn4.setTextFill(Color.BLUE);
}
if(det2 == 0)
{
btn1.setTextFill(Color.RED);
btn2.setTextFill(Color.RED);
btn3.setTextFill(Color.RED);
btn4.setTextFill(Color.RED);
btn5.setTextFill(Color.RED);
btn1.setText("NULL");
btn2.setText("NULL");
btn3.setText("NULL");
btn4.setText("NULL");
btn5.setText("NULL");
}
det2 = 0;
}
});
Thread.sleep(10000);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
The problem is that it freezes the UI every time it is executed. The freeze is longer when the internet is slow. How can I prevent the UI from freezing even if it is still gathering data from the url?
The UI thread freezes because you are still doing the all the logic on the JavaFX application Thread(Platform.runLater ).
You should do something like this instead:
public Void call() throws Exception
{
while (true)
{
try
{
//get json
} catch(Exception e)
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
//set buttons color and text here
}
}
}
//Rest of your logic here
}
}
The idea is that everything that is going to modify a UI component from a separate Thread should be handled in the Platform.runLater
If you use a background thread invoke Platform.runLater with a long-running Runnable as parameter, you've effectively achieved nothing. The Runnable is still run on the JavaFX application thread freezing your app.
Instead you should collect all the data on the background thread and process it to the point where you simply need to adjust some properties of the scene. Then you use Platform.runLater to do those updates.
But the good news is that there is a class designed for this scenario that could simplify your code a bit: ScheduledService.
Just make sure that you don't access the GUI in any way from the background thread (neither for reading nor for setting properties).
The following example simplified example should demonstrate the general approach. It calculates some multiples of the value chosen via Spinner on a background thread delaying 10 sec between each calculation:
#Override
public void start(Stage primaryStage) {
Spinner<Integer> spinner = new Spinner(1, 100, 1);
// ensure the value is available in a way that allows synchronisation
final AtomicReference<Integer> input = new AtomicReference<>(spinner.getValue());
spinner.valueProperty().addListener((o, oldValue, newValue) -> input.set(newValue));
final int outputCount = 10;
GridPane root = new GridPane();
root.add(spinner, 0, 0, 2, 1);
// create output grid
Text[] output = new Text[outputCount];
for (int i = 1; i <= output.length; i++) {
Text text = new Text(Integer.toString(spinner.getValue() * i));
output[i - 1] = text;
root.addRow(i, new Text("Value multiplied by " + i + " = "), text);
}
root.setPrefWidth(300);
ScheduledService<int[]> service = new ScheduledService<int[]>() {
#Override
protected Task<int[]> createTask() {
return new Task<int[]>() {
#Override
protected int[] call() throws Exception {
// retrieve value and set it to null to denote a change
// that was already handled to avoid doing unnecessary
// work
Integer value = input.getAndSet(null);
int[] result = null;
if (value != null) {
int valueAsInt = value;
result = new int[outputCount];
for (int i = 0; i < outputCount; i++) {
result[i] = (i + 1) * valueAsInt;
}
}
// simpulate delay
Thread.sleep(2000);
return result;
}
};
}
};
service.valueProperty().addListener((o, oldValue, newValue) -> {
// update GUI
if (newValue != null) {
for (int i = 0; i < outputCount; i++) {
output[i].setText(Integer.toString(newValue[i]));
}
}
});
service.setPeriod(Duration.seconds(10));
// make sure service uses a daemon thread
service.setExecutor(Executors.newSingleThreadScheduledExecutor((Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}));
service.start();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
I recommend looking through the javadoc of ScheduledService to get familiar with it's capabilities. It also allows for things like reacting to exceptions in the task and specifying a backoff strategy.
Is there any way of running a handler inside a loop?
I have this code but is not working as it does not wait for the loop but executes the code right way:
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
//
for (int i = 1; i < 6; i++) {
handler.postDelayed(this, 5000);
}
}
};
// trigger first time
handler.postDelayed(runnable, 0);
Of course when I move the post delayed outside the loop works but it does not iterate nor execute the times I need:
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
//
for (int i = 1; i < 6; i++) {
}
// works great! but it does not do what we need
handler.postDelayed(this, 5000);
}
};
// trigger first time
handler.postDelayed(runnable, 0);
SOLUTION FOUND:
I need to use asyntask along with Thread.sleep(5000) in the doInBackground method:
class ExecuteAsyncTask extends AsyncTask<Object, Void, String> {
//
protected String doInBackground(Object... task_idx) {
//
String param = (String) task_idx[0];
//
Log.d(TAG, "xxx - iter value started task idx: " + param);
// stop
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//
Log.d(TAG, "xxx - iter value done " + param);
return " done for task idx: " + param;
}
//
protected void onPostExecute(String result) {
Log.d(TAG, "xxx - task executed update ui controls: " + result);
}
}
for(int i = 0; i < 6; i ++){
//
new ExecuteAsyncTask().execute( String.valueOf(i) );
}
Instead of using a for loop, you can let the Runnable instance call itself for a specific number of times. These calls will be posted to UI thread queue so, keep that in mind. Also, since the delay is quite large, make sure the event is still needed when you trigger it next time.
The following code should do it:
final Handler handler = new Handler();
int count = 0;
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "Run test count: " + count);
if (count++ < 5) {
handler.postDelayed(this, 5000);
}
}
};
// trigger first time
handler.post(runnable);
Here is a simple logic I made, without moving the for loop inside runnable.
for(int i = 1; i<=5; i++){
...
new Handler().postDelayed(() -> myFunctionToExecute() , i * 1000);
}
So whenever the loop iterates, it just extends the handler delay. And this way, you may achieve. I was searching for something similar, couldn't find anything, because in my case I already did the implementation of for loop, moving it inside the run() creates a mess
My solution to this problem if anyone has simmilar issues:
int count = 0;
public static void method(param1, param2, param3) {
Runnable r = () -> { //put method inside runnable
View view = listView.getChildAt(position); //action to be complete
if (view != null) { //if action is successfully complete
view.setSelected(true); //do something with this
} else { //do a looper
if (count < 10) { //limited looper to certain number
count++;
method(param1, param2, param3); //run the method again
}
};
Handler h = new Handler(); //create a new Handler and post above thread with it
h.postDelayed(r, 300);
}
Basically, I have created an if-else statement where else statement runs the same method with postDelayed() again for a limited number of trials.
This can be another solution
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
int i;
public void run() {
for (i = 1; i < 6; i++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
}
}, 0);
//Add some downtime
SystemClock.sleep(5000);
}
}
};
new Thread(runnable).start();
I write some timer. and I want to display it in textview after start button is clicked.
What I did.
Every time I
timer = new Thread(new Runnable() {
#Override
public void run() {
while (!stopedButton ) {
time = "";
if (timerMinutes >= 60) {
timerMinutes = 0;
timerHours++;
}
if (timerHours < 10)
time = "0" + String.valueOf(timerHours) + ":";
else
time = String.valueOf(timerHours) + ":";
if (timerMinutes < 10)
time += "0" + String.valueOf(timerMinutes);
else
time += String.valueOf(timerMinutes);
runOnUiThread(new Runnable() {
public void run() {
if (!stopedButton) {
mTimeFromStartValue.setText(time);
timerMinutes++;
} else {
timerMinutes = 0;
timerHours = 0;
}
}
});
Log.e(TAG, ""+timerHours);
Log.e(TAG, ""+timerMinutes);
Log.e(TAG, time);
try {
Thread.sleep(1 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
so it works fine, but every time after stop and then start and after doing it many times my timer starts working fast. I try to avoid that kind of situation and I thought that i don't need to create new timer every time. But I need to have working timer after stop start too.
I wrote some code like this:
if(timer.isAlive()){
timer.resume();
}else{
timer.start();
}
But I have got this exception: java.lang.IllegalThreadStateException: Thread already started
so how to solve this ?
You need to create new Thread instance to start new thread. Also You need do use interrupt() method of Thread class.
Use this code to finish Your thread:
#Override
public void run() {
while (true) {
// Your code here
if(isInterrupted ()){
return;
}
}
}
Use this code when stop button was clicked:
timer.interrupt();
timer.join();
So my JProgressBar I have set up doesn't work the way I want it. So whenever I run the program it just goes from 0 to 100 instantly. I tried using a ProgressMonitor, a Task, and tried a SwingWorker but nothing I tried works.
Here is my program:
int max = 10;
for (int i = 0; i <= max; i++) {
final int progress = (int)Math.round(
100.0 * ((double)i / (double)max)
);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
jProgressBar2.setValue(progress);
}
});
}
#MadProgrammer Here is my attempt at making a swing worker and writing each name to the document and updating the progress bar. The program gets to around 86 percent and stops, never creating the finished document. The program creates a blank document. Here are the two methods first is the SwingWorker object I made:
public class GreenWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
int max = greenList.size();
XWPFParagraph tmpParagraph;
XWPFRun tmpRun;
FileInputStream file =
new FileInputStream(location + "GreenBandList.docx");
gDocument = new XWPFDocument(OPCPackage.open(file));
for (int i = 0; i < max; i++) {
tmpParagraph = gDocument.getParagraphs().get(0);
tmpRun = tmpParagraph.createRun();
if (greenList.get(i).length() == 1) {
tmpRun.setBold(true);
tmpRun.setText(greenList.get(i));
tmpRun.setBold(false);
} else {
tmpRun.setText(greenList.get(i));//Write the names to the Word Doc
}
int progress = Math.round(((float) i / max) * 100f);
setProgress(progress);
}
return null;
}
}
And here is the code for the button that starts it and has my property change event.
private void GenerateGreenList() throws IOException, InterruptedException {
//Need to fix the bug that removes the Letter Header in Yellow Band list
//********************************************************************\\
//Delete the old list and make a new one
File templateFile = new File(location + "\\backup\\GreenTemplate.docx");
FileUtils.deleteQuietly(new File(location + "GreenBandList.docx"));
FileUtils.copyFile(templateFile, new File(location +
"GreenBandList.docx"));
//Get the New Entries
String[] entries = jTextPane3.getText().split("\n");
for (String s : entries) {
if (s != null) {
greenList.add(s);
}
}
//Resort the list
Collections.sort(greenList);
//Write the names to the document
GreenWorker worker = new GreenWorker();
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
jProgressBar2.setValue((Integer) evt.getNewValue());
}
}
});
worker.execute();
if (worker.isDone()) {
try {
gDocument.write(new FileOutputStream(new File(location + "GreenBandList.docx")));
////////////////////////////////////////////////////////////
} catch (IOException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
JOptionPane.showMessageDialog(null, "Green Band List Created!");
jProgressBar2.setValue(0);
}
}
I used the property change listener from one of your other posts but I don't really understand what the one you wrote does or what it does in general?
Swing is a single threaded environment, that is, there is a single thread which is responsible for processing all the events that occur within the system, including repaint events. Should anything block this thread for any reason, it will prevent Swing from processing any new events, including, repaint events...
So all this ...
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex); }
jProgressBar2.setValue(progress);
}
});
Is constantly pausing the Event Dispatching Thread, preventing it from actually doing any updates (or at least spacing them randomly)...
It's also likely that your outer loop is been run from within the context of the EDT, meaning that until it exists, nothing in the Event Queue will be processed. All your repaint requests will be consolidated down to a single paint request and voila, instant filled progress bar...
You really should use a SwingWorker - I know you said you tried one, but you've not shown any code as to your attempt in this regards, so it's difficult to know why it didn't work, however...
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and dual welding JProgressBar example
SwingWorker and JProgressBar example
And forgive me if we haven't said this a few times before :P
You are evoking Thread.sleep inside the EvokeLater which means that it is running on another thread than your for loop. i.e., your for loop is completing instantaneously (well, however long it takes to loop from 1 to 100, which is almost instantaneously).
Move Thread.sleep outside of EvokeLater and it should work as you intend.
int max = 10;
for (int i = 0; i <= max; i++) {
final int progress = (int)Math.round(
100.0 * ((double)i / (double)max)
);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
jProgressBar2.setValue(progress);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
Edit: agree with #MadProgrammer. It appears this is just an illustrative question, but you should make sure whatever you're trying to accomplish here you use a SwingWorker for.