I am learning android. I made this stopwatch app work from my reference book.It only shows Hour:minutes:seconds but I want to add milliseconds right to the seconds.how do I do that.
code::-
public class StopWatchActivity extends AppCompatActivity {
int seconds;
boolean running;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stop_watch);
runTimer();
}
public void startTimer(View view){
running = true;
}
public void stopTimer(View view){
running = false;
}
public void resetTimer(View view){
running = true;
seconds = 0;
}
public void runTimer(){
final TextView textView = (TextView) findViewById(R.id.timer);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
int sec = seconds % 60;
String time = String.format("%d:%02d:%02d", hours,
minutes,sec);
textView.setText(time);
if(running) {
seconds++;
}
handler.postDelayed(this, 1000);
}
});
}
}
The first step would be to change the field seconds to milliSeconds because you want to keep track of that TimeUnit.
When restarting your handler with handler.postDelayed(this, 1000); define 1 millisecond as delay instead of 1000 (= 1 Second) like this handler.postDelayed(this, 1); then you just need to adjust your calculations and you are done :-)
An easier solution would be:
Instead of saving the elapsed seconds in your activity, save the time that the timer started (e.g. startTime)
Then, in your handler's runnable, get the current time and subtract the start time to find the elapsed time.
Pseudocode:
long startTimeNanos
public void runTimer() {
startTime = new Date()
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
long currentTime = System.nanoTime()
long elapsedNanos = currentTime - startTimeNanos
// calculate seconds and millis
// and set the textview text
handler.postDelayed(this, 1000);
}
});
}
This way, you can change the time that the handler fires and it won't affect anything else.
Related
I'm currently using a runnable and handler to have a timer which updates a textview every second.
public class TimerFragment extends Fragment {
TextView tvTimer;
long startTime = 0;
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
long millis = System.currentTimeMillis() - startTime;
int seconds = (int)(millis/1000);
int minutes = seconds / 60;
seconds = seconds % 60;
tvTimer.setText(String.format("%d:%02d", minutes, seconds));
timerHandler.postDelayed(this,500);
}
};
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag_timer, null);
tvTimer = (TextView)view.findViewById(R.id.tvTimer);
Button btn = (Button)view.findViewById(R.id.btn1);
btn.setText("Start");
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Button b = (Button) v;
if (b.getText().equals("Stop")){
timerHandler.removeCallbacks(timerRunnable);
b.setText("Start Monitoring");
}
else {
startTime = System.currentTimeMillis();
timerHandler.postDelayed(timerRunnable, 0);
b.setText("Stop");
Toast.makeText(getActivity(),"Monitoring started.",Toast.LENGTH_SHORT).show();
}
}
});
return view;
}
}
How do i get the value of the timer? Like for example, showing a toast when the text becomes "0:15". I want to be able to get the value so I can use it. The function I have in mind is having the user set a time and have a toast or notification pop up when the timer passes through that time (like 15 or 30 seconds). But right now what I want to know is how to get the value of the timer. Thanks!
You should use a CountDownTimer to set a countdown based on interval set by you and it will stop when the time has come in future
CountDownTimer(long millisInFuture, long countDownInterval)
// Example : I've set countdown for 30 seconds
CountDownTimer countDownTimer = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
text_view.setText(millisUntilFinished / 1000 + " " + "Sec");
}
public void onFinish() {
// implement your code customization here after interval is over
text_view.setText("time over!");
}
}.start();
For more insights refer the Android Developer reference for CountDownTimer
I want to create countdown timer that start from 5 secs and by pressing a button, the current time increase by 3 secs.
I used a handler to handle the countdown timer, I know we can`t use CountdownTimer.
Here is my code:
Handler handler = new Handler();
int delay = 1000;
r = new Runnable() {
#Override
public void run() {
int timeOut = finalTime - 1;
String printedTime = Integer.toString(timeOut);
timer.setText(printedTime);
handler.postDelayed(this,delay);
};
I updated, Here is the correct code in simple way:
timer = (TextView) findViewById(R.id.timer);
addSecs = (Button) findViewById(R.id.addSecs);
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
currentTime = timer.getText().toString();
time = Integer.parseInt(currentTime);
time-=1;
updateTime = Integer.toString(time);
timer.setText(updateTime);
handler.postDelayed(this,1000);
}
},1000);
addSecs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
currentTime = timer.getText().toString();
time = Integer.parseInt(currentTime);
time+=3;
updateTime = Integer.toString(time);
timer.setText(updateTime);
}
});
Use can change below code according to your logic timer
use CountDownTimer
1st param is the starting timer in miliseconds,
2st params is count down interval
new CountDownTimer(5000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
//5 ,4 , 3, 2, 1
Log.d(TAG,"starting nuclear in " + (millisUntilFinished/1000));
}
#Override
public void onFinish() {
//finish code
}
}.start();
If you want to use Handler
timeOut = 5;
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* do what you need to do */
Log.d(TAG,"starting nuclear in " + timeOut--);
/* and here comes the "trick" */
if(timeOut > 0)
handler.postDelayed(this, 1000);
}
};
private Handler handler = new Handler();
handler.postDelayed(runnable, 1000);
i've created a small app of memory game. in that app i have created a timer that show the time that take the user to finish the game. my problem is that the timer freeze after i go to another page (like home screen) and back to the game- the time remain at the same time it was stopped.....(i khnow it related somehow to onRestarte() method but dont know what to do..) i want that the timer will continue at the same time it has been stopped. (like if the user have an incall in the middle of the game and then want to continue).
package com.example.kineret.memorygame;
public class Game4x4Activity extends AppCompatActivity implements View.OnClickListener{
TextView timerTextView;
long startTime = 0;
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
long millis = System.currentTimeMillis() - startTime;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
timerTextView.setText(String.format("%d:%02d", minutes, seconds));
timerHandler.postDelayed(this, 500);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game4x4);
timerTextView = (TextView) findViewById(R.id.timerTextView4x4);
}
#Override
public void onPause() {
super.onPause();
timerHandler.removeCallbacks(timerRunnable);
}
#Override
public void onClick(View view) {
if(newGame) {
startTime = System.currentTimeMillis();
timerHandler.postDelayed(timerRunnable, 0);
newGame = false;
}
// rest of my code...
}
i have edited your code. plz try this
public class Game4x4Activity extends AppCompatActivity implements View.OnClickListener{
// make a new variable
static long elapsedTime = 0;
TextView timerTextView;
long startTime = 0;
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
// change here
long millis = (System.currentTimeMillis() - startTime) + elapsedTime;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
timerTextView.setText(String.format("%d:%02d", minutes, seconds));
timerHandler.postDelayed(this, 500);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game4x4);
timerTextView = (TextView) findViewById(R.id.timerTextView4x4);
}
#Override
public void onPause() {
// change here
elapsedTime = elapsedTime + (System.currentTimeMillis() - startTime);
timerHandler.removeCallbacks(timerRunnable);
super.onPause();
}
#Override
public void onResume() {
super.onResume();
// change here
if(!newGame) {
startTime = System.currentTimeMillis();
timerHandler.postDelayed(timerRunnable, 0);
}
}
If the user gets a phone call your app will call onPause then if they finish their phone call and play your game your activity will get onResume called.
in onPause save the system time, in onResume get the latest system time. Take these away from each other (in onResume) and you will have the time that the user was not in your app, you can then add this to your timer before you restart it.
You may also have to persist this time with onSaveInstanceState at other points.
I want to do countdown timer with pause and restart.Now i am displaying countdown timer By implenting ontick() and onfinish().please help me out.HEre is th code for countdown timer
final CountDownTimer Counter1 = new CountDownTimer(timervalue1 , 1000)
{
public void onTick(long millisUntilFinished)
{
System.out.println("onTick method!"(String.valueOf(millisUntilFinished/1000)));long s1=millisUntilFinished;
}
public void onFinish()
{
System.out.println("Finished!");
}
}
in onTick method..save the milliseconds left
long s1=millisUntilFinished;
when you want to pause the timer use..
Counter.cancel();
when you want to resume create a new countdowntimer with left milliseconds..
timervalue=s1
counter= new Counter1();
counter.start();
See this link
I would add something to the onTick handler to save the progress of the timer in your class (number of milliseconds left).
In the onPause() method for the activity call cancel() on the timer.
In the onResume() method for the activity create a new timer with the saved number of milliseconds left.
Refer the below links
LINK
LINK
My first answer on stackOverFlow, hope it should help :) ...
This is how I solved the problem, control timer from Fragment, Bottomsheet, Service, Dialog as per your requirement, keep a static boolean variable to control.
declare in your Activity:
long presetTime, runningTime;
Handler mHandler =new Handler();
Runnable countDownRunnable;
Toast toastObj;
public static boolean shouldTimerRun = true;
TextView counterTv;
In onCreate:
presetTime =60000L;
runningTime= presetTime;
//setting up Timer
countDownRunnable=new Runnable() {
#Override
public void run() {
if (shouldTimerRun) //if false, it runs but skips counting
{
counterTv.setText(simplifyTimeInMillis(runningTime));
if (runningTime==0) {
deployToast("Task Completed"); //show toast on task completion
}
runningTime -= 1000;
presetTime = runningTime; //to resume the timer from last position
}
mHandler.postDelayed(countDownRunnable,1000); //simulating on-tick
}
};
mHandler.post(countDownRunnable); // Start our CountdownTimer
Now, whenever you want to pause the timer change the value of shouldTimerRun false and to resume make it true.
#Override
public void onResume() {
super.onResume();
shouldTimerRun=true;
}
#Override
public void onPause() {
super.onPause();
shouldTimerRun=false;
deployToast("Timer is paused !!");
}
Helping methods: (can be skipped)
public static String simplifyTimeInMillis(long time) {
String result="";
long difference = time;
long secondsInMilli = 1000;
long minutesInMilli = secondsInMilli * 60;
long hoursInMilli = minutesInMilli * 60;
if (difference<1000){
return "0";
}
if (difference>=3600000) {
result = result + String.valueOf(difference / hoursInMilli) + "hr ";
difference = difference % hoursInMilli;
}
if (difference>=60000) {
result = result + String.valueOf(difference / minutesInMilli) + "m ";
difference = difference % minutesInMilli;
}
if (difference>=1000){
result = result + String.valueOf(difference / secondsInMilli) + "s";
}
return result;
}
public void deployToast(String msg){
if (toastObj!=null)
toastObj.cancel();
toastObj = Toast.makeText(mContext,msg,Toast.LENGTH_SHORT);
toastObj.show();
}
I'm using two private vars in this case:
private long startPauseTime;
private long pauseTime = 0L;
public void pause() {
startPauseTime = System.currentTimeMillis();
}
public void resumen(){
pauseTime += System.currentTimeMillis() - startPauseTime;
}
I am afraid that it is not possible to pause or stop CountDownTimer and pausing or stopping in onTick has no effect whatsoever user TimerTask instead.
Set up the TimerTask
class UpdateTimeTask extends TimerTask {
public void run() {
long millis = System.currentTimeMillis() - startTime;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
timeLabel.setText(String.format("%d:%02d", minutes, seconds));
}
}
if(startTime == 0L) {
startTime = evt.getWhen();
timer = new Timer();
timer.schedule(new UpdateTimeTask(), 100, 200);
}
You can add event listener's like this..
private Handler mHandler = new Handler();
...
OnClickListener mStartListener = new OnClickListener() {
public void onClick(View v) {
if (mStartTime == 0L) {
mStartTime = System.currentTimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
}
}
};
OnClickListener mStopListener = new OnClickListener() {
public void onClick(View v) {
mHandler.removeCallbacks(mUpdateTimeTask);
}
};
For more refer to Android Documentation.
//This timer will show min:sec format and can be paused and resumed
public class YourClass extends Activity{
TextView timer;
CountDownTimer ct;
long c = 150000; // 2min:30sec Timer
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.YourXmlLayout);
timer = (TextView)findViewById(R.id.Yourtimer)
startTimer(); // it will start the timer
}
public void startTimer(){
ct = new CountDownTimer(c,1000) {
#Override
public void onTick(long millisUntilFinished) {
// Code to show the timer in min:sec form
// Here timer is a TextView so
timer.setText(""+String.format("%02d:%02d",millisUntilFinished/60000,(millisUntilFinished/1000)%60));
c = millisUntilFinished; // it will store millisLeft
}
#Override
public void onFinish() {
//your code here
}
};
ct.start();
}
/*===========================================================
*after creating this you can pause this by typing ct.cancel()
*and resume by typing startTimer()*/
public class MainActivity extends AppCompatActivity {
TextView textView;
CountDownTimer ctimer;
boolean runCountDown;
private long leftTime;
private static final long MILL_IN_FUTURE = 6000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text_view);
textView.setText("Click to start");
textView.setOnClickListener(this::clickStartAndPauseAndResume);
leftTime = MILL_IN_FUTURE;
}
public void clickStartAndPauseAndResume(View view) {
if (!runCountDown) {
long time = (leftTime == 0 || leftTime == MILL_IN_FUTURE) ? MILL_IN_FUTURE : leftTime;
ctimer = new CountDownTimer(time, 1) {
#Override
public void onTick(long l) {
leftTime = l;
textView.setText(l + "ms");
}
#Override
public void onFinish() {
textView.setText("Done");
leftTime = 0;
runCountDown = false;
textView.postDelayed(new Runnable() {
#Override
public void run() {
textView.setText("Click to start");
}
}, 1000);
}
}.start();
runCountDown = true;
} else {
ctimer.cancel();
textView.setText(textView.getText() + "\n Click to resume");
runCountDown = false;
}
}
}
A nice and simple way to create a Pause/Resume for your CountDownTimer is to create a separate method for your timer start, pause and resume as follows:
public void timerStart(long timeLengthMilli) {
timer = new CountDownTimer(timeLengthMilli, 1000) {
#Override
public void onTick(long milliTillFinish) {
milliLeft=milliTillFinish;
min = (milliTillFinish/(1000*60));
sec = ((milliTillFinish/1000)-min*60);
clock.setText(Long.toString(min)+":"+Long.toString(sec));
Log.i("Tick", "Tock");
}
The timerStart has a long parameter as it will be reused by the resume() method below. Remember to store your milliTillFinished (above as milliLeft) so that you may send it through in your resume() method. Pause and resume methods below respectively:
public void timerPause() {
timer.cancel();
}
private void timerResume() {
Log.i("min", Long.toString(min));
Log.i("Sec", Long.toString(sec));
timerStart(milliLeft);
}
Here is the code for the button FYI:
startPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(startPause.getText().equals("Start")){
Log.i("Started", startPause.getText().toString());
startPause.setText("Pause");
timerStart(15*1000);
} else if (startPause.getText().equals("Pause")){
Log.i("Paused", startPause.getText().toString());
startPause.setText("Resume");
timerPause();
} else if (startPause.getText().equals("Resume")){
startPause.setText("Pause");
timerResume();
}
I have a timer in android to countdown to a future date, but it is not refreshing. Any help appreciated. my code is posted below:
public class Activity1 extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView t = (TextView)findViewById(R.id.countdown);
t.setText(timeDif());
I believe that t.setText just needs to be constantly updated, but am unsure of how to do that.
}
public String timeDif()
{
GregorianCalendar then = new GregorianCalendar(2012, 07, 21, 6, 0, 0);
Calendar now = Calendar.getInstance();
long arriveMilli = then.getTimeInMillis();
long nowMilli = now.getTimeInMillis();
long diff = arriveMilli - nowMilli;
int seconds = (int) (diff / 1000);
int minutes = seconds / 60;
seconds %= 60;
int hours = minutes / 60;
minutes %= 60;
int days = hours / 24;
hours %= 24;
String time = days + ":" +zero(hours)+":"+zero(minutes)+":"+zero(seconds);
return time;
}
private int zero(int hours) {
// TODO Auto-generated method stub
return 0;
}
}
The textbox wont update unless you do it in its own thread. The Timer runs on a different thread than the UI. Here is how I did it.
myTimer = new Timer();
myTimerTask = new TimerTask() {
#Override
public void run() {
TimerMethod();
}
};
myTimer.schedule(myTimerTask, 0, 100);
private void TimerMethod()
{
//This method is called directly by the timer
//and runs in the same thread as the timer.
//We call the method that will work with the UI
//through the runOnUiThread method.
if (isPaused != true) {
this.tmrMilliSeconds--;
this.runOnUiThread(Timer_Tick);
}
}
private Runnable Timer_Tick = new Runnable() {
public void run() {
//This method runs in the same thread as the UI.
if (tmrSeconds > 0) {
if (tmrMilliSeconds <= 0) {
tmrSeconds--;
tmrMilliSeconds = 9;
}
} else {
Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(1000);
myTimer.cancel();
tmrSeconds = setTime;
tmrMilliSeconds = 0;
isPaused = true;
}
//Do something to the UI thread here
timerText.setText(String.format("%03d.%d", tmrSeconds, tmrMilliSeconds));
}
};
That is part of the code for a count down clock I made for an ap. It demonstrates how to have one thread run (The public void run()) part, and then another part that runs on the UI thread. Hope that helps.
You shouldn't be doing this with a timer. A timer uses a thread and you don't need one (and it complicates things unnecessarily). You need to use a Runable and Handler's postDelayed method to do it. It is easier and lighter weight.
Handler mHandler = new Handler();
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
//update here
mHandler.postDelayed(mUpdateTimeTask, 100);
}
};
private void startTimer()
{
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
}