How to stop Runnable on button click in Android? - android

I have to start runnable on start button click and stop it on pause button click.
My code for start runnable on start button click is
// TODO Auto-generated method stub
//while (running) {
mUpdateTime = new Runnable() {
public void run() {
sec += 1;
if(sec >= 60) {
sec = 0;
min += 1;
if (min >= 60) {
min = 0;
hour += 1;
}
}
Min_txtvw.setText(String.format(mTimeFormat, hour, min, sec));
mHandler.postDelayed(mUpdateTime, 1000);
}
};
mHandler.postDelayed(mUpdateTime, 1000);
//}
now i want to stop that runnable on pause button click
pause_btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
play_btn.setVisibility(View.VISIBLE);
pause_btn.setVisibility(View.INVISIBLE);
}
});
How can i stop that runnable on pause button click if anyone knows please help me.

Use
mHandler.removeCallbacksAndMessages(runnable);
in pause button click.

Keep a boolean cancelled flag to store status. Initialize it to false and then modify it to true on click of stop button.
And inside your run() method keep checking for this flag.
Edit
Above approach works usually but still not the most appropriate way to stop a runnable/thread. There could be a situation where task is blocked and not able to check the flag as shown below:
public void run(){
while(!cancelled){
//blocking api call
}
}
Assume that task is making a blocking api call and then cancelled flag is modified. Task will not be able to check the change in status as long as blocking API call is in progress.
Alternative and Safe Approach
Most reliable way to stop a thread or task (Runnable) is to use the interrupt mechanism. Interrupt is a cooperative mechanism to make sure that stopping the thread doesn't leave it in an inconsistent state.
On my blog, I have discussed in detail about interrupt, link.

Complete Code:
iterationCount = 0;
final Handler handler = new Handler();
final int delay = 1000; //milliseconds
handler.postDelayed(new Runnable() {
public void run() {
//do something
if (iterationCount < 10) {
handler.postDelayed(this, delay);
}
iterationCount++;
Log.e("tag", "after 1 second: " + iterationCount);
}
}, delay);

Use below code :
handler.removeCallbacks(runnable);

Thread thread;
//inside start button
thread=new Thread(new Runnable() {
#Override
public void run() {
sec += 1;
if(sec >= 60) {
sec = 0;
min += 1;
if (min >= 60) {
min = 0;
hour += 1;
}
}
Min_txtvw.setText(String.format(mTimeFormat, hour, min, sec));
mHandler.postDelayed(mUpdateTime, 1000);
});
thread.start();
//inside stop button
mHandler.removeCallbacksAndMessages(runnable);
thread.stop();

Related

How do I stop this Thread in Android?

While learning using Threads in Android I've created simple thread that updates time textview every second:
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
if(time!=0){
if(time>9){timeLeftTV.setText("0:"+time);}
else{timeLeftTV.setText("0:0"+time);}
time--;
}
else {
//timeLeftTV.setText("finished");
}
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
I want to display dialog box when the time expires. How do I stop this thread?
use CountDownTimer
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
This is example of 30 seconds for 1 second time interval.
You can display dialog box on onFinish() method.
Most of the time I use a Runnable that can be scheduled with a Handler as followed:
final int timeInterval = 1000;
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run () {
textView.setText("time..");
// schedule the same Runnable after one second
handler.postDelayed(this, timeInterval);
}
};
handler.postDelayed(runnable, timeInterval);
To stop your loop, remove the Runnable from the Handler:
handler.removeCallbacks(runnable);
When you don't want to use the method above, simply use a Boolean that prevents your loop to continue and your Thread will end itself:
boolean stop = false;
Thread t = new Thread() {
#Override
public void run () {
while (!stop) {
// do stuff
}
}
};
t.start();
To stop the Thread:
stop = true;
Just interrupt the thread, Where you want to stop it.
thread.interrupt();
There are many ways to stop thread.
Like you can use Executor Services instead of timer. But for the quick solution you can go ahead with the following one:
long startTimer= System.currentTimeMillis();
long stopTimer= startTimer+ 60*1000; // 60 seconds * 1000 ms/sec
while (System.currentTimeMillis() < stopTimer)
{
// Perform your all the required operation here
}
Hope it will help you.
For Executor service check the below stack link:
How to timeout a thread

Restart countodown timer with different timer android

I am making a repeating countdown timer app.I require the countdown timer to restart with a different time.I am using a global variable in the constructor of the countdown timer.But the problem is that it always restarts from the starting of the first given interval.
public void chance(final int tota, final int cur, final int exercise,int pass,int flag)
{
Log.i("inside value","reached");
a = new CountDownTimer((tempmilliseconds) * 1000 + 100, 1000) {
#Override
public void onTick(long millisUntilFinished) {
tempmilliseconds = (int) millisUntilFinished / 1000;
Log.i("inside value",Integer.toString(tempmilliseconds));
updatetimer(millisUntilFinished);
}
#Override
public void onFinish() {
mtext.setText("0:00");
cancel();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
currentcompleted++;
if (on == 0) {
on = 1;
int exercis = MainActivity.restmint * 60 + MainActivity.restsec;
tempmilliseconds=exercis;
chance(tota, curr + 1, exercis, 0, 0);
} else {
on = 0;
int exercis = MainActivity.exermint * 60 + MainActivity.exersec;
tempmilliseconds=exercis;
chance(tota, curr + 1, exercis, 0, 0);
}
}
}, 1000);
}
};
a.start();
}
Below is the code for resume operations:
public void resume(View view) {
Button mytext=(Button) findViewById(R.id.resume);
if( mytext.getText().toString()=="Pause") {
mytext.setText("Play");
a.cancel();
}
else {
mytext.setText("Pause");
Log.i("Value of temp",Integer.toString(tempmilliseconds));
a.start();
}
}
The timer is stopping but when started in the resume function restarts with the original time and not specified by tempmilliseconds.Note tempmilliseconds is updated every seconds.
Any help/snippets/suggestions is appreciated.Thank you!
A CountDownTimer will not allow itself to be disturbed in any case. It will remember the time it was born with till someone kills it.
If you look at its documentation you'd see that it directly inherits from Object class and has only four methods: start(), cancel(), onFinish() (abstract) and onTick() (abstract). Thats pretty much it. So, you basically are left with no choice but to call cancel() and then re-initialise the timer. Or, you can extend the CountDownTimer class and encapsulate this under the hood.
In either case the cost of cancelling ad re-initialising may get tedious.

Stop repeating timer android

I want to create 10 ImageViews with a delay of 5 seconds between, I created this code:
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (counter <= 10)
newimg();
else
// here I want to stop the timer so it will not try to create any more `ImageViews` (the array contains only 10).
}
}, 0, 5000);
private void newimg() {
ball[counter] = new ImageView(this);
ball[counter].setTag(counter);
ball[counter].setBackgroundResource(R.mipmap.ball);
int randomx = rand.nextInt(layoutwidth);
int randomy = rand.nextInt(layoutheight);
ball[counter].setX(randomx);
ball[counter].setY(randomy);
rlt.addView(ball[counter]);
counter++;
}
How can I stop the timer inside the else statement?
Call Timer cancel to stop the timer.
Call cancel() on timer
My Solutions is :
Handler handler = new Handler();
handler.postDelayed(createImageView, 5000);
Runnable createImageView=new Runnable() {
#Override
public void run() {
if (counter <= 10){
handler.postDelayed(this,5000);
newimg();
}
}
};

Textview not showing aftert couple of VISIBLE and INVISIBLE set

First, I used animation to hide and show TextView. I saw that using animation costing memory. So I used another way:
SetVisibility(VISIBLE) and SetVisibility(INVISIBLE) with TaskTimer
it works well and it performs better considering the memory.
The main issue is that after a restarting the timer for many times, the TextView disappear.
I need to restart the app to get it back again!
this is the code snippet:
myTimerForAnimation = new Timer();
myTimerForAnimation.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() // run on ui thread
{
public void run() {
counter++;
if (counter < 7) {
if (counter % 2 == 1) {
list_textView[x].setVisibility(View.INVISIBLE);
} else {
list_textView[x].setVisibility(View.VISIBLE);
}
} else {
myTimerForAnimation.cancel();
myTimerForAnimation.purge();
list_textView[x].setVisibility(View.VISIBLE);
}
}
});
}
}, 1000, 600);
Dont use Timer use handler,something like this:
// init the runnables
// the runnable should be members
Handler hanlder = new Handler();//If you arent on the UI thread pass a correct looper
for (int i=1; i<7 ; i++){
long delay = i * 1000;
if (i%2==0)
{
handler.postDelayed(mVisibleRunnable,delay);
}else{
handler.postDelayed(mInVisibleRunnable,delay);
}
}
Whereas the get runnablebs should be memebers because if u choose to cancel the callbacks then call
handler.removeCallbacks(runnable);
Play with it. It should fix your issue.
thanks to #EE66 for the loop idea, I used this code to solve my problem:
private void animateView(final View view){
for (int counter = 0; counter < 7; counter++) {
long delay = counter * 1000;
if (counter % 2 == 0) {
view.postDelayed(new Runnable() {
public void run() {
view.setVisibility(View.VISIBLE);
}
;
}, delay);
} else {
view.postDelayed(new Runnable() {
public void run() {
view.setVisibility(View.INVISIBLE);
}
;
}, delay);
}
}
}

How to play a sound a set number of times?

I'm developing an application to do the following:
When you pressed a button, the application plays a sound lasting two seconds, five times. After playing the sound for the fifth time the application sleeps for thirty seconds. After sleeping, the cycle is repeated two more times.
My problem is that I can not stop the sound after it plays for the fifth time. I think I need to use the for loop or a while loop, but I cannot program them correctly.
The loop:
for(i=0; i==5; ) {
sound.start();
if(sound.isPlaying()) {
if(false) {
sound.stop();
i++;
}
}
}
sound.stop();
well, now I built this code, but his only fault is the 'for' not working properly ... he is not repeat the code that is inside of him twice.
someone can tell me why?
for( counter=0; counter<2; ++counter){
new CountDownTimer(20000, 2000) {
public void onTick(long millisUntilFinished) {
//call to my UI thread every 2 seconds
sound.start();
}
public void onFinish() {
//final call to my UI thread after 10 seconds
chrono2.setBase(SystemClock.elapsedRealtime());
chrono2.start();
chrono2.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
public void onChronometerTick(Chronometer chronometer) {
// TODO Auto-generated method stub
long elapsedTime = SystemClock.elapsedRealtime()-chronometer.getBase();
Log.i(this.getClass().getName(), "" + elapsedTime);
if (elapsedTime > 10000){
chrono2.stop();
chrono2.setBase(SystemClock.elapsedRealtime());
Toast.makeText(getApplicationContext(), "" , Toast.LENGTH_SHORT).show();
}
}
});
} // end onFinish
}.start(); // end count down
}
for(i=0; i==5; ) {
sound.start();
if(sound.isPlaying()) {
if(false) {
sound.stop();
i++;
}
}
}
sound.stop();
The second part of the for loop header is a condition which has to hold for the body to be entered. i=0 and i == 5 don't match, so the condition is wrong from the start and never entered.
You want to experess
for(i=0; i!=5; ) {
or
for(i=0; i<5; ) {
instead.
But where is i incremented or somehow else changed? In a block which is always false, in other words: Never.
Maybe you want to express that, if the statement before is false, do ...
You do so by negating the statement:
if (! sound.isPlaying ()) {
sound.stop();
i++;
}
Without knowing whether sound-playing is blocking or not it is hard to know how to control it.
Let's read the requirements and do it from scratch:
When you pressed a button, the application plays a sound lasting two
seconds, five times. After playing the sound for the fifth time the
application sleeps for thirty seconds. After sleeping, the cycle is
repeated two more times.
You have an outer loop of 3 times, and an inner loop of 5 times.
for (int i=0; i < 3; ++i) {
for (int j=0; j < 5; ++j) {
sound.start();
sleep (2); // seconds of sound
}
sleep (30); // seconds of silence
}
Just keep a counter variable that will tell the application to sleep when it has reached 5, in your while loop. Pseudo code is something like this :
final int REPEAT_RATE = 5;
int counter = 0;
while(counter < 3 * REPEAT_RATE)
{
if(counter == REPEAT_RATE)
{
//Sleep for thirty seconds
}
//Here Play the sound for 2 seconds
}
That is easy all you need is to use a count down timer:
new CountDownTimer(10000, 2000) {
public void onTick(long millisUntilFinished) {
//call to my UI thread every 2 seconds
playSound();
}
public void onFinish() {
//final call to my UI thread after 10 seconds
}
}.start();
And use a simple timer to sleep 30 seconds:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//do after 30 seconds
}
}, 30000);
By adjusting and combining these two you can make your effect...
EDIT: a solution (untested)
int repeatAlarm = 3; //above onCreate
....
playSoundFiveTimes(); //in onCreate
.......
private void playSoundFiveTimes(){
new CountDownTimer(10000, 2000) {
public void onTick(long millisUntilFinished) {
sound.stop();
sound.start();
}
public void onFinish() {
repeatAlarm--;
if(repeatAlarm > 0) wait30seconds();
}
}.start();
}
private void wait30seconds(){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
playSoundFiveTimes();
}
}, 30000);
}
this is my solution:
you can use seekTo(0) function
then mp start again!
private void startCountDownTimer() {
cdTimer = new CountDownTimer(total, 1000) {
public void onTick(long l) {
mp.seekTo(0);
mp.start();
}
public void onFinish() {
mp.stop();
MediaPlayer doneMp = MediaPlayer.create(getApplicationContext(), R.raw.finished_challenge);
doneMp.start();
}
}.start();
}

Categories

Resources