My project is a radio app and I want to add a sleep timer so that the user can set it to close the app after a specified time.
Please use startTimer(long ms) to start countdown timer and cancel timer to stop. And use wakelock to continue timer after screen off.
CountDownTimer cTimer = null;
void startTimer(long time) {
if(!wakeLock.isHeld()) {
PowerManager mgr = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SonaHeartLock");
wakeLock.acquire();
}
cTimer = new CountDownTimer(time, 1000) {
public void onTick(long millisUntilFinished) {
timerSync = millisUntilFinished;
}
public void onFinish() {
timerSync = 0;
System.exit(0);
}
};
cTimer.start();
}
//cancel timer
void cancelTimer() {
if (cTimer != null) {
timerSync = 0;
cTimer.cancel();
cTimer=null;
if(wakeLock!=null && wakeLock.isHeld())
wakeLock.release();
}
}
Thread.sleep(2000);
will pause for 2 seconds (i.e 2000 ms). In an Android app I wrote several years ago I actually had:
Thread.currentThread().sleep(2000);
but I'm pretty sure the .currentThread() was not needed. I was just learning Java at the time.
See Oracle's doc.
In more detail, what I actually had was a separate task:
class TimerUpdater extends AsyncTask<String, String, Void>{
}
That periodically checked the time (pausing using Thread.sleep()) and displayed a countdown, and at zero set a flag that the main task periodically checked and ended the game when it saw it was set.
My app was terrible code, but I was learning both Java and Android at the same time as fast as I could, to make an app to help my kid in math class.
Android has changed a lot since then, though.
You can get the time from user and after that you can create one background process which count time everytime and check with user time. If both will match then immediately close your app
Related
I'm trying to reproduce the beep.wav sound each second from 3 to 1 , for example, reproduce 3 , 2, and 1 the beep sound, and then when finish reproduce the beependsound.
For some reason only the beependsound is playing but when reaching second 3 it seems the ui freezes for a sec and then the numbers decrease fast to 0
private void stopPlaying(){
if(mp!=null){
try {
mp.reset();
mp.prepareAsync();
mp.stop();
mp.release();
mp=null;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
private void startCountDown() {
aCounter = new CountDownTimer(10000, 100) {
public void onTick(long millisUntilFinished) {
if (Math.round((float) millisUntilFinished / 1000.0f) != secondsLeft) {
countDownTxt.setTextColor(getResources().getColor(R.color.white));
secondsLeft = Math.round((float) millisUntilFinished / 1000.0f);
countDownTxt.setText(String.valueOf(secondsLeft));
}
if (secondsLeft <= 3) {
countDownTxt.setTextColor(getResources().getColor(R.color.colorAccent));
stopPlaying();
mp = MediaPlayer.create(MainActivity.this, R.raw.beep);
mp.start();
}
}
public void onFinish() {
secondsLeft = 0;
stopPlaying();
mp = MediaPlayer.create(MainActivity.this, R.raw.beepend);
mp.start();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
aCounter.cancel();
startCountDown();
}
}, 1000);
}
};
aCounter.start();
}
I spect this to work as described above, any hint ?
MediaPlayer.create() can be a fairly expensive call. Consider what happens if it takes approximately 100ms (or even more):
The timer calls onTick().
onTick() blocks for about 100ms inside MediaPlayer.create().
mp starts playing, and onTick() returns. (So far, so good!)
Immediately, the timer realizes another onTick() call is due! The last one started over 100ms ago!
onTick() is called again, almost immediately. Very quickly, it reaches the stopPlaying() call. But you only started playing about 1ms ago!
This leads to a situation where your timer spends all its time in MediaPlayer.create(), and almost no time actually playing the sound.
Note that, with the code as written, it will attempt to play the sound approximately 30 times in the last 3 seconds of the countdown (since the ticks are ideally 100ms apart). If your intent was to play the sound only 3 times, you may want to move your second if block to inside the first. That way, you only attempt play when secondsLeft actually changes. This will actually ameliorate the original problem, and you may not need any further changes.
But if you want to optimize further, note that you can prepare mp in advance -- say, when the app starts up -- and simply reuse it: Instead of release()-ing it each time, just stop() it, and prepare() it (and don't reset() it). That'll leave it ready for the next play. You could even create a separate MediaPlayer just for beepend, and you could prepare them both during app initialization.
the program that i am making includes two different count down.
first, user has to type in the password within the time limit and press a button. If user can't input the password before the time limit, then it is over. However, if the user was able to input the password correctly before the time limit, a new timer should start.
public class MalibuCountDownTimer extends CountDownTimer
{
public MalibuCountDownTimer(long startTime, long interval)
{
super(startTime, interval);
}
#Override
public void onFinish()
{
if(hasPlanted == false) {
text.setText("Time's up!");
mTextView.setText("cya");
btnEnable(false);
startB.setEnabled(false);
}
}
#Override
public void onTick(long millisUntilFinished)
{
text.setText(""+String.format("%02d:%02d:%03d",
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)),
TimeUnit.MILLISECONDS.toMillis(millisUntilFinished) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished))
));
}
}
this is the first timer, and it is working just fine. However, i am having trouble trying to stop this timer when user entered the correct password.
I have created another class of CountDownTimer, and when the user input the correct password within the time limit, the second timer starts. I put a boolean to stop the first timer to do anything when it ends, but I have no idea how I can fully stop that counter.
if(myTimer != null) {
myTimer.cancel();
myTimer = null;
}
This is in order to cancel the timer early. First check if it is null, and if it isn't, apply the cancel method on it. Let me know if this was helpful.
:)
First you have to create service and call that service in main class where timer is running and call the onReceive method
BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Here you check the timer is running or not
timer.cancel();
}
};
I have implemented a class which extends a CountDownTimer and it works good, but when the screen is turned Off, the timer is desynchronized, so the idea is that, when I get out of the activity or the screen is Off, the CountDownTimer should be continue working properly. I have the permission <uses-permission android:name="android.permission.WAKE_LOCK"/>, also I have tried with PowerManager, but I think the problem is not there.
PowerManager pm = (PowerManager) getSystemService((MenuApp.this).POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
myTimer = new CustomTimer(min, 1000);
myTimer.start();
wl.release();
.
#TargetApi(Build.VERSION_CODES.GINGERBREAD) #SuppressLint("NewApi")
public class CustomTimer extends CountDownTimer
{
public CustomTimer(long millisInFuture, long countDownInterval)
{
super( millisInFuture, countDownInterval );
byteTimer = 1;
}
#TargetApi(Build.VERSION_CODES.GINGERBREAD)
#SuppressLint("NewApi")
#Override
public synchronized void onTick(long millisUntilDone)
{
String hms = String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millisUntilDone)- TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millisUntilDone)),
TimeUnit.MILLISECONDS.toSeconds(millisUntilDone)-TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilDone)));
tim.setText(hms);
edit.putLong("Minute", millisUntilDone-1669);
edit.commit();
}
#TargetApi(Build.VERSION_CODES.GINGERBREAD)
#SuppressLint("NewApi")
#Override
public synchronized void onFinish()
{
tim.setText("00:00");
seconds = 0L;
if(btnToggle.isChecked()){
btnToggle.setChecked(false);
btnToggleTimer.setChecked(false);
}else{
btnToggle.setChecked(true);
btnToggleTimer.setChecked(false);
}
}
}
What do you recommend me to do?
The clunky answer is to do what you tried to do: keep the CPU on all the time. You would acquire() the WakeLock before you start the timer and only release() it when you stop the timer. However, users will want to do nasty things to you with pointy sticks if you keep the CPU on all the time during the countdown, as that drains the battery. It also may be tricky to not screw up and leak the WakeLock, forgetting to release() it in some scenario, causing the CPU to remain on so long as your process continues running. That might be enough to cause users to come after you with heavier weaponry.
Hence, don't use CountDownTimer. Instead, use AlarmManager (to get control when the countdown is over, even if the device is asleep) and something lightweight (e.g., a postDelayed() loop) to keep updating the UI while you happen to be in the foreground. This will minimize the battery drain while still giving you control at the right time.
I am creating application which works with SMS service and FTP networking.
If user does not establish connectivity, it will try to reconnect again in 30 seconds.
I am using CountDownTimer with TextView to inform user about time left to reconnnect.
Either it will be successful or it will start counting again.
My problem is, that if counter restarts while activity is in background or the screen is locked, TextView keeps showing number "1" (it won't update) until the timer restarts again in foreground (but updating numbers without timer restart works fine in backround or lock, I am using wakelock in my foreground service).
After counter restarts again (so it won't stop counting) while application is in foreground, everything comes back to normal, TextView updates from freezed "1" to "30" and starts counting down to "1".
I think problem will be somewhere in communication between counter thread and background activity with UI, but I don't know nothing more about it.
I tried several things like:
creating setter and getter for miliseconds and update them in each
tick, then try to update textview from onReume(), didn't work.
create local variable for TextView inside timer, initialize it inside onTick() and
try to update text from there, also didn't work.
Thanks everyone for help, I will appriciate any advices.
Part of code relative to question:
private CountDownTimer cdt = null;
private final TextView getTextView_ActivityMainMenu_Timer(){
return (TextView) findViewById(R.id.ActivityMainMenu_TextView_Timer);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getBooleanExtra("KEY_FAILED", false)){
cdt = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
getTextView_ActivityMainMenu_Timer().setText("" + millisUntilFinished / 1000);
}
public void onFinish() {
;
}
}
.start();
}
else
{
if(cdt != null)
cdt.cancel();
}
}
};
Finally I found solution of this problem. I didn't realize that I am unregistering the receiver in onPause() method. So I had to change it and put registration of broadcast into onResume() and unregister it only in onDestroy() method.
At onCreate, I run a task that repeats every minute. Here how I do it:
myTimer = new Timer();
int delay = 30000; // delay for 30 sec.
int period = 600000; // repeat every 60 sec.
doThis = new TimerTask() {
public void run() {
Log.v("TImer","repeated");
wv.reload();
}
};
myTimer.scheduleAtFixedRate(doThis, delay, period);
All that code is in onCreate. So, when the app goes off from the screen, I can see in logcat that timer steel runs, and will not stop unless the app will be destroyed. So, in onPause of activity I call myTimer.cancel(); but it didnt help. I still can see updates in logcat, even when the app is not on the screen. So, how to stop timerTask?
Here is your code put into my file, with the values delay and period tweaked so I don't have to wait so long. I run the app. I see the messages in LogCat. I press the home button on my Galaxy S3. Then the messages stop in LogCat.
public class MainActivity extends Activity {
Timer myTimer;
TimerTask doThis;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTimer = new Timer();
int delay = 0; // delay for 30 sec.
int period = 1000; // repeat every 60 sec.
doThis = new TimerTask() {
public void run() {
Log.v("TImer","repeated");
}
};
myTimer.scheduleAtFixedRate(doThis, delay, period);
}
#Override
protected void onPause() {
myTimer.cancel();
super.onPause();
}
}
It could be that since the thread has already been sent out, it runs one last time. In the onLoad set a variable to true, then in the onPause set it to false. Then in your timer task only run your code if the variable is true.
Write to the log outside of the new if statement though. If it is indeed running it just one last time, then that might be your solution. But if it is still running it over and over multiple times after the onPause then don't take my solution.
The actual answer is: The onPause method needs to be defined correctly.
The whole story:
The questioner defined the onPause method wrong. That was the reason for asking this question.
I'm writing this because I spent too much time reading question, answers, code and comments. The real answer was hidden in the last comment.