CountDownTimer fire twice? - android

I have a method to detect is the amplitude below a threshold.
public boolean amplitude_Detection(double ampA) {
//Thresholds for amplitude acceleration
double acceAmplitudeTH = 3.0;
//Compare value with threshold
if (ampA < acceAmplitudeTH) {
return true;
}
return false;
}
Then next in my onSensorChanged, I have if statement if the code above return true, I want to pause my sensor for 5 seconds. After 5 seconds, resume the sensor again. However, during my experiment by throwing phone on bed 10 times in a same position. The timer sometimes will be fired twice and sometimes just one. Anyone know what's happening?
if(algo.amplitude_Detection(ampA))
{
//Pause sensors
pauseSensor();
Toast.makeText(getBaseContext(), "Pause ", Toast.LENGTH_SHORT).show();
new CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) {
((TextView)findViewById(R.id.timeCalc)).setText("Time Left: "+millisUntilFinished/1000+"\n"+ampA);
}
public void onFinish() {
((TextView)findViewById(R.id.timeCalc)).setText("Done");
resumeSensor();
}
}.start();
}
}
public void pauseSensor()
{
senManager.unregisterListener(this, sensorAccelerometer);
}
public void resumeSensor() {senManager.registerListener(this, sensorAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);}

Related

Running backgound thread every X seconds (Android Studio)

I have a code that plays 5 sounds with 1 second delay between the sounds and I want this part of code to be executed every 5 seconds (so it will run in a row so far as a boolean variable is true, and when it becomes false the tread run stopped - I have a button to both start and stop this executions). Everything works perfectly, but the issue is that I can't get rid of the 5 seconds delay in the first time I click the button, so when I first click, the sounds beggins only after 5 seconds. How can I make it start right away and only after the first time start taking the delays?
Here is the button onClick code:
public void clickHandlerStartTempo(final View view) {
if (!tempoOn) {
Toast toast = Toast.makeText(getApplicationContext(), "Start Tempo!", Toast
.LENGTH_SHORT);
toast.show();
tempoOn = true;
final Handler handler = new Handler();
final int delay = 5000; //milliseconds
handler.postDelayed(new Runnable() {
public void run() {
if (tempoOn) {
runCode(view);
handler.postDelayed(this, delay);
}
}
}, delay);
} else {
Toast toast = Toast.makeText(getApplicationContext(), "Stop Tempo!", Toast
.LENGTH_SHORT);
toast.show();
tempoOn = false;
}
}
And here is the runCode method:
public void runCode(View view) {
Runnable runnable = new Runnable() {
#Override
public void run() {
playSound(0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 4; i++) {
if (tempoOn) {
playSound(1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
return;
}
}
}
};
Thread thread = new Thread(runnable);
Log.i(TAG, "runCode: Thread id = " + thread.getId());
thread.start();
}
I'm new to android development and any help would be very much appreciated.
Thanks.
First you need to playsound without thread after that you will execute your reaming 5 second logic stop thread after 4 count.
public void onStartPress(){
playSound();
someMethod();
}
public void someMethod(){
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.postDelayed(new Runnable() {
#Override
public void run() {
playSound();
someMethod();
}
},1000);
}
Don't use actual Threads unless you really want to do something off the Ui thread. Most of the time you do want to keep things on the Ui thread.
For simple repeating tasks, you can easily repurpose the CountDownTimer class. Often with an (almost) infinite run time or Long.MAX_VALUE (292 million years). The fist onTick happens immediately after starting.
private CountDownTimer mTimer;
private void start() {
if (mTimer == null) {
mTimer = new CountDownTimer(Long.MAX_VALUE, 5000) {
#Override
public void onTick(long millisUntilFinished) {
// start a beeping countdown
new CountDownTimer(5000, 1000) {
private int state = 1;
#Override
public void onTick(long millisUntilFinished) {
playSound(state);
state = state + 1 % 2;
}
#Override
public void onFinish() {
playSound(0);
}
}.start();
}
#Override
public void onFinish() { /* ignore, never happens */ }
};
mTimer.start();
}
}
private void stop() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}

Return boolean value from CountDownTimer

I have a 5 seconds count down timer and I need to detect the amplitude of acceleration within the duration. If the amplitude meet the statement, a true will be return. However, due to the void method OnTick and also it is an inner class, I couldn't return or pass any value to outer class.
public boolean low_high_Detection(final double ampA) {
new CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) {
final double low_TH = 9.0, high_TH = 10.5;
boolean lying_on_floor = false;
if(ampA > low_TH && ampA <high_TH)
{
lying_on_floor = true;
}
}
public void onFinish() {
Toast.makeText(detect.getBaseContext(), "5 seconds dectection over",Toast.LENGTH_SHORT).show();
}
}.start();
if (lying_on_floor == true)
{
return true;
}
return false;
}
Anyone can suggest me how can I fix this method? Or there is another way to deal with it.
This can be achieved with an anonymous class as a listener.
Declare an interface which actues as a listener.
public interface LowHightDetectionListener {
void onDetected(boolean result);
}
Then, to call this method and pass an instance of this listener to the method low_high_Detection()
low_high_Detection(ampA, new LowHightDetectionListener {
#Override
public void onDetected(boolean result) {
// Process the result
}
});
Here you get the "returned" value.
To return the desired value inside the low_high_Detection() method you need to call the listener.
public void low_high_Detection(final double ampA, final LowHightDetectionListener callback) {
new CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) {
final double low_TH = 9.0, high_TH = 10.5;
boolean lying_on_floor = false;
if(ampA > low_TH && ampA <high_TH) {
lying_on_floor = true;
callback.onDetected(true); // EXAMPLE OF RETURNING VALUE INSIDE AN ANONYMOUS CLASS
}
}
public void onFinish() {
Toast.makeText(detect.getBaseContext(), "5 seconds dectection over",Toast.LENGTH_SHORT).show();
}
}.start();
if (lying_on_floor == true) {
callback.onDetected(true);
return;
}
callback.onDetected(false);
}
}

How to use CountDownTimer in my android application?

I'm writing a android application. I have a CountDownTimer in between my application and i want until the timer to zero, all my app run(user must be select the true Button) and when become zero and the user did'nt anything, the other action performed (the user loses).
this is CountDownTimer :
new CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) {
a.setText("" + millisUntilFinished / 1000);
/*while (millisUntilFinished / 1000 != 1) {
}*/
}
public void onFinish() {
a.setText("done!");
}
}.start();
and this is part of code:
if ((randomAndroidColor1 == rainbow[0]) {
findViewById(ans).setBackgroundColor(rainbow2[0]);
findViewById(ans).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
c3.setBackgroundColor(rainbow1[2]);
}
});
}
How to access to millisUntilFinished variable in above if condition?
Timer and if condition worked correctly but I want to combine them.
If I understood correctly , you can use an instance boolean variable.
boolean isWon = false;
private void countDown() {
isWon=false; // Reset every method call.
// Set listener once in method.
findViewById(R.id.answer).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
isWon=true;
}
});
new CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) {
// onTick works.
}
public void onFinish() {
if(isWon){
// Won
}else{
// Lose
}
}
}.start();
}

problems with CountDownTimerWithPause

I'm trying to use this timer, like on this question suggested:
https://stackoverflow.com/questions/13806545/how-to-extend-countdown-timer-with-pause,
but doesn't work as expected. The pause/resume works fine, but if I cancel and recreate the timer, then the counting starts from the last paused time. I need to start from the initial value.
For eg the counter's intial value is 3 minutes. If I paused it at 2 minutes, then when I'm trying to create it again it starts from 2 minutes.
Any help?
public class MainActivity extends ButtonMethods implements OnClickListener {
private CountDownTimerWithPause timerPausable = null;
int milis = 180000;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
timerPausable = new CountDownTimerWithPause(milis, 1000, true)
{
#Override
public void onTick(long millisUntilFinished)
{
timer.setText("" + millisUntilFinished / 1000);
}
#Override
public void onFinish()
{
timer.setText("180");
DisableRandomButtons();
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bNewWord:
if(clicked == false){
clicked = true;
timerPausable.create();
}
else{
clicked = false;
timerPausable.cancel();
timerPausable=null;
milis=180000;
timerPausable.create();
}
break;
case R.id.imageView2:
tapsound.start();
if(isclicked == false){
isclicked = true;
timerPausable.pause();
}
else{
isclicked = false;
timerPausable.resume();
}
break;
Its hard to say what your exact problem is without seeing your code but what I did was call cancel() on my timer then make it equal to null to reset it. Mine is a little different and I handle it in onBackPressed()
#Override
public void onBackPressed()
{
super.onBackPressed();
timer.cancel(); // timer is a reference to my inner CountDownTimer class
timer = null;
secs = 10;
}
I think this is what you are looking for. It works for me.

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