My intention is to create an timer which starts from 00:00:00 and hangs together with a recording function. This recording is done in a service so, the timer is also in the same service. If the app moves to the background, the recording and thus the timer keep on going and the app picks the time up at the onResume with a myService.getTime().
But I experience two strange things. The first is that my timer sometimes goed faster than a second, sometimes slower, sometimes jumps from for example 00:00:04 to 00:00:06 etc. There is no consitency in it. I use the code below, but there might be a better option to solve this? The second is that it is causing a lag on my button, although I am starting it in a service?
SERVICE
//////////TIMER FUNCTION START//////////
private void startTimerClick() {
if (stopped) {
startTime = System.currentTimeMillis() - elapsedTime;
} else {
startTime = System.currentTimeMillis();
}
mHandler.removeCallbacks(startTimer);
mHandler.postDelayed(startTimer, 0);
}
private void pauseTimerClick() {
mHandler.removeCallbacks(startTimer);
stopped = true;
}
private void stopTimerClick() {
mHandler.removeCallbacks(startTimer);
stopped = false;
}
private void startTimer() {
startTimer = new Runnable() {
public void run() {
elapsedTime = System.currentTimeMillis() - startTime;
updateTimer(elapsedTime);
mHandler.postDelayed(this, REFRESH_RATE);
}
};
}
private void updateTimer(float time) {
secs = (long) (time / 1000);
mins = (long) ((time / 1000) / 60);
hrs = (long) (((time / 1000) / 60) / 60);
/*
* Convert the seconds to String and format to ensure it has a leading
* zero when required
*/
secs = secs % 60;
seconds = String.valueOf(secs);
if (secs == 0) {
seconds = "00";
}
if (secs < 10 && secs > 0) {
seconds = "0" + seconds;
}
/* Convert the minutes to String and format the String */
mins = mins % 60;
minutes = String.valueOf(mins);
if (mins == 0) {
minutes = "00";
}
if (mins < 10 && mins > 0) {
minutes = "0" + minutes;
}
/* Convert the hours to String and format the String */
hours = String.valueOf(hrs);
if (hrs == 0) {
hours = "00";
}
if (hrs < 10 && hrs > 0) {
hours = "0" + hours;
}
}
//////////TIMER FUNCTION END////////////
public String getHours(){
return hours;
}
public String getMinutes(){
return minutes;
}
public String getSeconds(){
return seconds;
}
}
ACTIVITY(/FRAGMENT)
private void timerStart() {
handler = new Handler();
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
handler.post(new Runnable() {
#Override
public void run() {
timer.setText(myService.getHours()+":"+myService.getMinutes()+":"+myService.getSeconds());
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
}
You are using Threads both in your Service and in your Activity/Fragment code.
Using threads for time sensitive tasks in Android is a problem because Android is able to significantly delay threads.
I have been using a ScheduledThreadPoolExecutor for a similar task and it worked great.
You are then using it like this:
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); // where 1 is the number of needed concurrent threads. 1 should last for your needs.
executor.scheduleWithFixedDelay(new TimerTask() {
// your recurringly executed code here
}, 0, 1, TimeUnit.SECONDS);
Related
I have two activity set countdown timer in MainActivity, I want when countdown timer finished it will go next activity.but it's not going to next activity its show timer.
here is my code:
public class MainActivity extends AppCompatActivity {
TextView txtViewDays,txtViewHours,txtViewMinutes,txtViewSecond;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtViewDays = findViewById(R.id.days);
txtViewHours = findViewById(R.id.hours);
txtViewMinutes = findViewById(R.id.minutes);
txtViewSecond = findViewById(R.id.seconds);
start_countdown_timer();
}
private void start_countdown_timer()
{
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy, HH:mm:ss");
formatter.setLenient(false);
final long[] startTime = new long[1];
String endTime = "23.06.2019, 22:56:10";
long milliseconds=0;
final CountDownTimer mCountDownTimer;
Date endDate;
try {
endDate = formatter.parse(endTime);
milliseconds = endDate.getTime();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
startTime[0] = System.currentTimeMillis();
mCountDownTimer = new CountDownTimer(milliseconds, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Long serverUptimeSeconds =
(millisUntilFinished - startTime[0]) / 1000;
String daysLeft = String.format("%d", serverUptimeSeconds / 86400);
txtViewDays.setText(daysLeft);
String hoursLeft = String.format("%d", (serverUptimeSeconds % 86400) / 3600);
txtViewHours.setText(hoursLeft);
String minutesLeft = String.format("%d", ((serverUptimeSeconds % 86400) % 3600) / 60);
txtViewMinutes.setText(minutesLeft);
Log.d("minutesLeft",minutesLeft);
String secondsLeft = String.format("%d", ((serverUptimeSeconds % 86400) % 3600) % 60);
txtViewSecond.setText(secondsLeft);
}
#Override
public void onFinish() {
Intent i = new Intent(MainActivity.this,New.class);
startActivity(i);
finish();
}
};
mCountDownTimer.start();
}
}
What can I do?
N.B : code is collected and I also try but I can't.Thank you
With your code you need 1561330519961ms that means several days must pass in order for onFinish method to be called. I tried your code with 1min for the timer instead
milliseconds = endDate.getTime();
and worked just fine. After the timer finished it changed activity.
---edit---
This sample code will run for 6 seconds and then call the onFinish method
milliseconds = 6000
mCountDownTimer = new CountDownTimer(milliseconds, 1000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
Intent i = new Intent(MainActivity.this,Myclass.class);
startActivity(i);
finish();
}
};
mCountDownTimer.start();
I have following code in my service.
countDownTimer = new CountDownTimer(60000 * 3, 1000) {
#Override
public void onTick(long l) {
intentDSU.putExtra("remaind", TimeUnit.MILLISECONDS.toSeconds(l));
sendBroadcast(intentDSU);
}
#Override
public void onFinish() {
postHandler();
intentDSU.putExtra("remaind", 0);
sendBroadcast(intentDSU);
countDownTimer.start();
}
};
countDownTimer.start();
That's work fine, but when i try convert seconds to minutes and remaind of seconds on my activity
private void updateGUI(Intent intent){
if(intent.getExtras() != null){
long remaind = intent.getLongExtra("remaind", 0);
if(remaind == 0){
onRefresh();
}
long minutes = TimeUnit.SECONDS.toMinutes(remaind) - (TimeUnit.SECONDS.toHours(remaind)* 60);
long seconds = TimeUnit.SECONDS.toSeconds(remaind) - (TimeUnit.SECONDS.toMinutes(remaind) *60);
MenuItem menuItem = menu.findItem(R.id.action_timer);
if(menuItem != null){
if(minutes > 0){
menuItem.setTitle(String.format("%o min.", minutes));
}
else {
menuItem.setTitle(String.format("%o sec.", seconds));
}
}
}
}
I become notice unusual results, seconds will start 73 instead 60. I haven't idea, what's wrong?
you're code is correct, I quess you get problem in String.format("%o min.", minutes) and here String.format("%o sec.", seconds).
Try to use this.
MenuItem menuItem = menu.findItem(R.id.action_timer);
if(menuItem != null){
if(minutes > 0){
menuItem.setTitle(String.format("%s min.", Long.toString(minutes)));
}
else {
menuItem.setTitle(String.format("%s sec.", Long.toString(seconds)));
}
}
try this
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
long sec=TimeUnit.MILLISECONDS.toSeconds(passmillitimer);
I have strange problem with countdowntimer. Normally it works well, but sometimes (like 5% chance or so) after locking phone and unlocking it bugs like on video:
https://www.dropbox.com/s/1nbp63gmv4spzgf/bug.mp4
Here i set the timer:
private void startCurrentLessonTimer() {
if(lessonsBreak) {
lessonsBreakEnd.setText(String.format("%02d:%02d:%02d", (currentLessonTimeInMillis / 1000) / 3600, ((currentLessonTimeInMillis / 1000) % 3600) / 60,
(currentLessonTimeInMillis / 1000) % 60));
} else {
currentLessonEnd.setText(String.format("%02d:%02d:%02d", (currentLessonTimeInMillis / 1000) / 3600, ((currentLessonTimeInMillis / 1000) % 3600) / 60,
(currentLessonTimeInMillis / 1000) % 60));
}
currentLessonTimer = new CountDownTimer(currentLessonTimeInMillis, 1000) {
long hours = (currentLessonTimeInMillis / 1000) / 3600;
long minutes = ((currentLessonTimeInMillis / 1000) % 3600) / 60;
long seconds = (currentLessonTimeInMillis / 1000) % 60;
#Override
public void onTick(long millisUntilFinished) {
if(seconds == 0) {
seconds = 59;
if(minutes == 0 && hours > 0) {
minutes = 59;
hours--;
}
else {
minutes--;
}
} else {
seconds--;
}
if(lessonsBreak) {
lessonsBreakEnd.setText(String.format("%02d:%02d:%02d", hours, minutes, seconds));
} else {
currentLessonEnd.setText(String.format("%02d:%02d:%02d", hours, minutes, seconds));
}
}
#Override
public void onFinish() {
getNextLesson();
getCurrentLesson();
}
}.start();
}
And this function (inside getData()) is called in onResume()
#Override
public void onResume() {
super.onResume();
getData();
}
onPause():
#Override
public void onPause() {
super.onPause();
clean();
}
clean():
private void clean() {
if(currentLessonTimer != null) {
currentLessonTimer.cancel();
currentLessonTimer = null;
}
}
I tried to use other countdowntimer, but this problem still occurs (but not that often).
Code: http://pastebin.com/nKsasJ1S
Any ideas?
It looks like you get multiple CountDownTimers refreshing your UI. This leads me to your clean() function like it's not doing it's job on every onPause(). So on next onResume() there will be multiple CountDownTimers.
I don't know how CountDownTimer works but the thing I can think of is that your CountDownTimer is start()ed but still not initialized (currentLessonTimer is still null) when onPause() is occurring not letting clean() to run so it'd be a race condition that could be avoided with a Service for example.
The timer works fine for starting then reseting and leaving the view, but if I start the time then leave the view and return and just hit Reset the app crashes. I know that most people would not hit reset when the timer is not started, but for idiot proofing I need a fix for this any suggestions?
public void startTimer(View view) {
final Handler handler = new Handler();
Timer ourtimer = new Timer();
timerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
int sec = n % 60;
int min = n / 60;
TextView timer = (TextView) findViewById(R.id.androidtimer);
timer.setText("" + String.format("%02d", min) + ":"
+ String.format("%02d", sec));
// timer.setText(n + " Seconds");
n++;
}
});
}
};
ourtimer.schedule(timerTask, 0, 1000);
}
public void stopTimer(View view) {
timerTask.cancel();
TextView timer = (TextView) findViewById(R.id.androidtimer);
timer.setText("--:--");
timerTask = null;
n = 0;
}
I think your problem is that timerTask is null as long as you do not start the timer.
So a simple if clause might help. If that's not the problem please post the exception.
public void stopTimer(View view) {
if(timerTask != null) {
timerTask.cancel();
}
TextView timer = (TextView) findViewById(R.id.androidtimer);
timer.setText("--:--");
timerTask = null;
n = 0;
}
A bit confusing this one but should make sense.
Thanks to all your help I have my app now showing a custom digital clock and a countdowntimer (02:30:00 countdown) running under it.
How do I add 02:30:00 to the current time so a new clock field shows the current time + the countdown?
Thanks
Dj
This is my digitalclock code where would i put the offset to ad 2 hours 30 mins to time...
#Override
protected void onStart() {
super.onStart();
timer = new Timer("DigitalClock");
Calendar calendar = Calendar.getInstance();
final Runnable updateTask = new Runnable() {
public void run() {
countdown.setText(getCurrentTimeString());
}
};
int msec = 999 - calendar.get(Calendar.MILLISECOND);
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(updateTask);
}
}, msec, 1000);
}
#Override
protected void onStop() {
super.onStop();
timer.cancel();
timer.purge();
timer = null;
}
private String getCurrentTimeString() {
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
// int second = calendar.get(Calendar.SECOND);
return String.format("%02d:%02d", hour, minute);
}
Now that I understand your question :p, I think the only way to do that is to reimplement a DigitalClock. Take its source code and play with it by adding an offset to the hours and minutes.
UPDATE:
What I would do is take that code and change this part:
mTicker = new Runnable() {
public void run() {
if (mTickerStopped) return;
mCalendar.setTimeInMillis(System.currentTimeMillis());
setText(DateFormat.format(mFormat, mCalendar));
invalidate();
long now = SystemClock.uptimeMillis();
long next = now + (1000 - now % 1000);
mHandler.postAtTime(mTicker, next);
}
};
mTicker.run();
Convert 2:30:00 to milliseconds and add it to now :
long now = SystemClock.uptimeMillis() + offset;