I just want to display the values of each iteration in the loop proceeded by 2 seconds delay.
when i run the code, the main thread freezes and after a while only the value of tv_t1: 19 is displayed.
can anyone please let me know what is the error or what i am missing in the below posted code?
NOTE :
I would like to do so on the main thread.
*Code
tv_t1 = (TextView) findViewById(R.id.tv_t1);
tv_t2 = (TextView) findViewById(R.id.tv_t2);
for(int i = 0; i < 20; i++) {
tv_t1.setText("t1:" + i);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Thread is Android's main/UI thread, and setting sleep(value) causes the main thread to sleep or
to stop doing its work for a scheduled time. If you want to update the main UI and sleep for a while, it is better to create a new thread and then create Runnable object that overrides Run(). And inside Run() you can call the function that is time consuming or also you can cause the new thread you created to sleep instead of forcing the UI thread to sleep which will cause all the main UI elements to freeze. The Handler in the below code works as intermediate between the thread and the message queue, you can also replace h1 with your tv_1 to post that as message into the queue and subsequently to update your view.
Please try the below code:
Handler h1 = new Handler();
Thread t1;
t1 = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
loop();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.start();
protected void loop() throws InterruptedException {
// TODO Auto-generated method stub
for (i = 0; i < 20; i++) {
t1.sleep(2000);
h1.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
tv_t1.setText("tv_1: " + i);
}
});
}
}
Thread.sleep on the UI Thread is a bad idea. Use an handler:
private Handler mHandler = new Handler():
private class MyRunnable implmenets Runanble {
private final static int MAX_INT = 20;
private int mCounter = 0;
#Override
public void run() {
if (mCounter == 20) {
mHandler.removeCallbacks(this);
return;
}
mytexts.setText(" " + mCounter);
mCounter++;
mHandler.postDelayed(this, 2000);
}
}
and in your create, after you initialze your views, call
mHandler.postDelayed(new MyRunnable(), 2000);
Maybe this will work out:
for(int i = 0; i < 20; i++) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
tv_t1.setText("t1:" + i);
}
}, 2000);
}
And yes if you get a delay when the value of "i" was 0 then set the first text outside the loop and start the loop with i=1 or put an if-else block inside the loop
Hope it helped.
Related
I want to make an option in my application that if you click a button a counter will start and it will count (like 0++) and show the number until user stops it, so far I have this non working code
if (v == btn3) {
counter = 0;
scoreText.setBackgroundColor(Color.RED);
new Thread(new Runnable() {
public void run() {
while (counter < 1000 ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
}).start();
scoreText.setText(Integer.toString(counter));
}
Currently when i press the button, the text field only turns red and is set to 0, but I can't make it count
In my opinion setText method is outside loop. It could update text view after loop ends. Move it somewhere inside loop.
This should work as per your needs
if (v == btn3) {
counter = 0;
scoreText.setBackgroundColor(Color.RED);
new Thread(new Runnable() {
public void run() {
while (counter < 1000 ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
scoreText.setText(Integer.toString(counter));
}
});
counter++;
}
}
}).start();
}
There is a a class called CountDownTimer which provides some useful functionality. In particular it provides an onTick() method with which you could update your text field at a desired interval.
You would need to create a CountDownTimer to count indefinitely, which you can do by restarting the timer in its onFinish() method, like in this question. But if you set the CountDownTimer for long enough, you probably would never need to restart it.
Something like this...
new CountDownTimer(<REALLY_BIG_NUMBER>, 500) {
int counter = 0;
public void onTick(long millisUntilFinished) {
scoreText.setText(counter++);
}
public void onFinish() {
start();
}
}.start();
the main problem is that I don't know how long my method will take to finish, I have 2 threads, one to execute the method that do stuff and the other one excute the progress of the progress bar, this is my first thread:
#Override
public void run() {
//This is a static variable, indicate when the method analyzeSentence finish
finish = false;
String sentence = analyzeSentence();
try {
Thread.sleep( 1000 );
} catch (InterruptedException e){
System.err.println( e.getMessage() );
}
finish = true;
}
And in my second thread (the progress bar thread) I have this:
#Override
public void run() {
i = 1;
while(!Analyze.finish) {
i = (i > 100) ? 1 : i+1; //Here I have the problem
progressBar.setValue(i);
progressBar.repaint();
try {
Thread.sleep(this.value);
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
if(Analyze.finish) {
progressBar.setValue(100);
break;
}
}
}
The problem is that the progress bar reset their values to zero but the method still not over so the progress bar is filled again and again... Is there any way to obtain the lenght of the time that the method takes to finish?
I have a thread that call's MainActivies method that sets text value of EditText but it fails.
MyRunnable is like that:
public class MyRunnable implements Runnable {
MainActivity mController;
public SoundTrigger(MainActivity pController) {
mController = pController;
}
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
if(i % 100) {
mController.triggered(i);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
In MainActivity class my triggered method like this:
public void triggered(int nNum) {
EditTextInstance.setText(nNum+"");
}
but it fails. All i need is printing a real time data that is created by a background thread on an edittext component.
make it like this:
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
if(i % 100) {
mController.runOnUiThread(new Runnable() {
public void run() {
mController.triggered(i);
}
});
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Explanation: you were previously changing an UI element from a Non-UI thread and this is not good. This code should work, BUT it is still not the recommended way to approach the problem. You should use something like a AsyncTask where you have a template method for 'background' operation (non-ui thread operation) and the 'onPostExecute' which already executes on the UI thread.
another additional note: NEVER call Thread.sleep(); on the UI Thread (a.k.a. Main thread)
I have a method myFuncs.requestData() that works standalone. It subcribes to listen for data and sets ReadyTxt="TRUE" when the listener has received all the data - which comes in multiple callbacks.
But, when I try to to check DataReady within the actionPerformed method that is attached to a button - it is unset because it appears that myFuncs.requestData() is only processed/run AFTER we come out of actionPerformed.
By "standalone" I mean that if I put no function at ##HERE## then the requestData() works after actionPerformed has completed.
How can I make sure it runs and wait for it to finish at the point ##HERE##?
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
writePaneln("BUTTON PRESSED "+myFuncs.ReadyTxt);
myFuncs.requestData();
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
}
writePaneln("REQUESTED "+myFuncs.ReadyTxt);
##HERE##
}
Threaded version:
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
writePaneln("BUTTON PRESSED "+myFuncs.ReadyTxt);
Thread thread = new Thread() {
public void run(){
myFuncs.requestData();
}
};
thread.start();
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
}
writePaneln("REQUESTED "+myFuncs.ReadyTxt);
##HERE##
}
simplified requestData():
public void requestData() {
DataReady="FALSE"
this.dataSubscription.setListener(this);
}
#Override
public void dataUpdated(List<long> updatedData) {
if (updatedData.size() <= 1 ){
this.dataSubscription.destroy();
writePaneln("In dataUpdated DataReady num: "+Dates.size());
DataReady="TRUE";
return;
}
for (long l: updatedData){
writePaneln(l);
Dates.add(l);
}
}
Answer seems to lie in using TimerTask to time a task for AFTER actioPerformed has completely finished becuase it seems to be on single thread.
http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html
Playing with OrderedExecutor, I tried using the CountDownLatch to start all the submitted tasks at the same time, but the tasks don't start, they're frozen.
Am i missing something?
import org.jboss.threads.OrderedExecutor;
final CountDownLatch taskUnfreezer = new CountDownLatch(1);
OrderedExecutor orderedExec = new OrderedExecutor(JBossExecutors.directExecutor(),10,JBossExecutors.directExecutor()) ;
orderedExec.executeNonBlocking(
new Runnable() {
#Override
public void run() {
try {
taskUnfreezer.await();
System.out.println("Task 1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
orderedExec.executeNonBlocking(
new Runnable() {
#Override
public void run() {
try {
taskUnfreezer.await();
System.out.println("Task 2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Try to start all tasks
taskUnfreezer.countDown();
You are using JBossExecutors.directExecutor(). This executor does not execute things in a separate thread, but instead executes tasks in the thread that calls execute (this is useful for testing).
Your code block on the first call to orderedExec.executeNonBlocking, since that is calling taskUnfreezer.await() in the same thread, and you will never get to taskUnfreezer.countDown()