I have a countdown timer that i want to implement on finish method or some kind of code so that when the timer stops, the text views change to Time's up and another method is initiated (in the activity).
To clarify, the timer is given a starting number that counts down from, to zero in format of xx:xx.
The class of the timer :
public class countdown_timer {
private long pls;
private long millisInFuture;
private long countDownInterval;
private boolean status;
public countdown_timer(long pMillisInFuture, long pCountDownInterval) {
this.millisInFuture = pMillisInFuture;
this.countDownInterval = pCountDownInterval;
this.pls = pMillisInFuture;
status = false;
Initialize();
}
public void Stop() {
status = false;
}
public void Reset() {
millisInFuture = pls;
}
public long getCurrentTime() {
return millisInFuture;
}
public void Start() {
status = true;
}
public void Initialize()
{
final Handler handler = new Handler();
Log.v("status", "starting");
final Runnable counter = new Runnable(){
public void run(){
long sec = millisInFuture/1000;
if(status) {
if(millisInFuture <= 0) {
Log.v("status", "done");
} else {
Log.v("status", Long.toString(sec) + " seconds remain");
millisInFuture -= countDownInterval;
handler.postDelayed(this, countDownInterval);
}
} else {
Log.v("status", Long.toString(sec) + " seconds remain and timer has stopped!");
handler.postDelayed(this, countDownInterval);
}
}
};
handler.postDelayed(counter, countDownInterval);
}
The activty that the timer is used:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_game_2);
//...find views
mycounterup = new countdown_timer(startcard, 1000);
mycounterdown = new countdown_timer(startcard, 1000);
RefreshTimer();
mycounterdown.Start();
public void RefreshTimer()
{
final Handler handler = new Handler();
final Runnable counter = new Runnable(){
public void run(){
int minutes_up_start = (int) (mycounterup.getCurrentTime() / 1000) / 60;
int seconds_up_start = (int) (mycounterup.getCurrentTime() / 1000) % 60;
String time_2_up_start_formatted = String.format(Locale.getDefault(), "%02d:%02d", minutes_up_start, seconds_up_start);
card_2_up.setText(time_2_up_start_formatted);
int minutes_down_start = (int) (mycounterdown.getCurrentTime() / 1000) / 60;
int seconds_down_start = (int) (mycounterdown.getCurrentTime() / 1000) % 60;
String card_2_down_start_formatted = String.format(Locale.getDefault(), "%02d:%02d", minutes_down_start, seconds_down_start);
card_2_down.setText(card_2_down_start_formatted);
handler.postDelayed(this, 100);
}
};
handler.postDelayed(counter, 100);
}
You can use CountDownTimer:
new CountDownTimer(endsIn * 1000, 1000) {
public void onTick(long millisUntilFinished) {
timerTextView.setText(String.valueOf(millisUntilFinished/1000);
}
public void onFinish() {
}
}.start();
OR:
extend CountDownTimer class:
public class countdown_timer extends CountDownTimer {
TextView textView;
#Override
public void onTick(long millisInFuture) {
long sec = millisInFuture/1000;
if(millisInFuture <= 0) {
Log.v("status", "done");
} else {
Log.v("status", Long.toString(sec) + " seconds remain and timer has stopped!");
}
}
#Override
public void onFinish() {
if(textView != null){
// change text in your textview
}
}
public countdown_timer(long pMillisInFuture, long pCountDownInterval) {
super(pMillisInFuture, pCountDownInterval);
}
public countdown_timer(TextView textView, long pMillisInFuture, long pCountDownInterval) {
super(pMillisInFuture, pCountDownInterval);
this.textView = textView;
}
}
here is a two constructors, one of them is the same as is in your example and in second one you can pass also TextView object and use it in onFinish() method.
UPDATE 2:
Here is CountDownTimer in the Activity:
public class MainActivity extends AppCompatActivity {
TextView textView;
CountDownTimer mycounterdown;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
long startcard = 10000;
textView = (TextView) findViewById(R.id.test);
mycounterdown = new CountDownTimer(startcard, 1000) {
#Override
public void onTick(long mycounterup) {
int minutes_up_start = (int) (mycounterup / 1000) / 60;
int seconds_up_start = (int) (mycounterup / 1000) % 60;
String time_2_up_start_formatted = String.format(Locale.getDefault(), "%02d:%02d", minutes_up_start, seconds_up_start);
textView.setText(time_2_up_start_formatted);
}
#Override
public void onFinish() {
// call here other methods from activity
testMethod();
}
};
mycounterdown.start();
}
public void testMethod(){
Toast.makeText(MainActivity.this, "Test Method called", Toast.LENGTH_SHORT).show();
}
}
UPDATE 3: if last tick is one, not zero change count down interval to 500 instead of 1000:
public class MainActivity extends AppCompatActivity {
TextView textView;
CountDownTimer mycounterdown;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
long startcard = 10000;
textView = (TextView) findViewById(R.id.test);
mycounterdown = new CountDownTimer(startcard, 500) {
#Override
public void onTick(long mycounterup) {
int minutes_up_start = (int) (mycounterup / 1000) / 60;
int seconds_up_start = (int) (mycounterup / 1000) % 60;
String time_2_up_start_formatted = String.format(Locale.getDefault(), "%02d:%02d", minutes_up_start, seconds_up_start);
textView.setText(time_2_up_start_formatted);
}
#Override
public void onFinish() {
// call here other methods from activity
testMethod();
}
};
mycounterdown.start();
}
public void testMethod(){
Toast.makeText(MainActivity.this, "Test Method called", Toast.LENGTH_SHORT).show();
}
}
NOTE: take a look at this answer
First, extend CountDownTimer in your timer class.
public class countdown_timer extends CountDownTimer {
}
This allows you to implement some methods.
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
}
Also you must implement constructor that matches super class. You can also add some additional parameters. For example TextView
TextView textView;
public countdown_timer(long millisInFuture, long countDownInterval, TextView txt) {
super(millisInFuture, countDownInterval);
textView = txt;
}
The onFinish() is what you want. Also make sure you are using this class as a CountDownTimer. Then you will be able to start your timer.
Hope it helps.
Related
I created a simple Java class. This should spend the time. With System.out.println it works too! But how can I inform a certain TextView that it should also change?
Countdown_Test.java
public class Countdown_test {
private static long START_TIME_IN_MILLIS;
private CountDownTimer mCountDownTimer;
private boolean mTimerRunning;
private long mTimeLeftInMillis;
//private TextView timer;
public Countdown_test(long start_time) {
START_TIME_IN_MILLIS = start_time;
mTimeLeftInMillis = START_TIME_IN_MILLIS;
//timer = findViewById(R.id.timer); dosen't work
}
public void startTimer() {
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimerRunning = false;
}
}.start();
mTimerRunning = true;
}
public void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
System.out.println(timeLeftFormatted);
}
}
MainActivity.java
Countdown_test ct = new Countdown_test(600000);
button_start.setOnClickListener(v -> {
ct.startTimer();
});
ct.updateCountDownText();
You could write an interface, a TimeLeftListener with a method onTimeLeftChanged(String timeleft). Then your activity extends TimeLeftListener and implements the onTimeLeftChanged()-method.
This is where you update your views.
When you initiate your CountDownTest you pass the activity like this.
Countdown_test ct = new Countdown_test(600000, this);
And create al listener in you CountDownTest-class like this
myTimeLeftListener =(TimeleftListener)activity;
Then in your updateCountDownText()-Method you put
myTimeLeftListener.onTimeLeftChanged(timeleft)
You could also use ViewModel and LiveData.
I have a simple stopwatch code piece. Thread is running in custom class, it connects to the main activity via Interface
public class MainActivity extends AppCompatActivity implements MainActivityInteractionInterface{
public static boolean isRunning = false;
Stopwatch stopWatch;
private TextView textViewMilliSeconds;
private TextView textViewSeconds;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textViewMilliSeconds = findViewById(R.id.textViewStopwatchMilliseconds);
textViewSeconds = findViewById(R.id.textViewStopwatchSeconds);
stopWatch = new Stopwatch(this, getApplicationContext());
stopWatch.runThread();
}
#Override
public void updateUI() {
String time = String.format(Locale.getDefault(), "%03d", stopWatch.getMilliseconds());
textViewMilliSeconds.setText(time);
String timeSeconds = String.format(Locale.getDefault(), "%02d", stopWatch.getSeconds());
textViewSeconds.setText(timeSeconds);
}
public void startTimer(View view) {
isRunning = !isRunning;
}
public class Stopwatch {
private int milliseconds = 0;
private int seconds = 0;
public int getMilliseconds() {
return milliseconds;
}
public int getSeconds() {
return seconds;
}
private MainActivityInteractionInterface interactionInterface;
private Context applicationContext;
public Stopwatch(MainActivityInteractionInterface interactionInterface, Context applicationContext){
this.interactionInterface = interactionInterface;
this.applicationContext = applicationContext;
}
public void runThread(){
final Handler handler = new Handler();
handler.post(new Runnable(){
#Override
public void run(){
if(isRunning) {
milliseconds++;
if (milliseconds == 1000) {
milliseconds = 0;
seconds++;
if(seconds == 60){
seconds = 0;
}
}
}
interactionInterface.updateUI();
handler.postDelayed(this, 1);
}
});
}
handler should update every 1 millisec, when there is 1000 milliseconds, 1 second passes by
If I set handler.postDelayed delay anything below 15 reaching 1000 milliseconds would take exactly 18 seconds, why?
I don't know why it would take up to 18seconds, but I can tell you this: Android refresh the UI every 16msec (to have a rate of 60fps), so setting the handler to updateUI in a lesser time would make no sense and maybe also interfier with it.
In my humble opinion, make it to update in 20msec and change the counter values according, like this:
handler.post(new Runnable(){
#Override
public void run(){
if(isRunning) {
milliseconds++;
if (milliseconds == 50) {
milliseconds = 0;
seconds++;
if(seconds == 60){
seconds = 0;
}
}
}
interactionInterface.updateUI();
handler.postDelayed(this, 20);
}
});
Look at the second argument of handler.postDelayed(this, 1);
Change it according to the way you increment your milliseconds.
I'm creating a timer app that utilizes a thread. When I exit the app using the home button the timer is running fine. Usually, when the time is up a dialog is launched that asks the user for some input. This works completely fine if the app is in its onResume() state, however when the app is in its onStop() state the dialog will not launch and an error is thrown.
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
How can I make it so that when the time is up and the app is NOT in the foreground the dialog is still launched. My initial thought was to save the time remaining in the bundle, but the time remaining is changing for every single tick. Then I thought about storing a boolean in the bundle mTimeRunning. However, when the time is up this value must also change. So now I'm drawing a blank. What can I possibly do so that the dialog is launched when the app is not in the foreground?
TimerActivity.java
public class TimerActivity extends AppCompatActivity implements TimeDialogFragment.sendMinutes,
TimeFinishDialogFragment.sendResponse, BreakFinishDialogFragment.userResponse {
// Variable to log activity state
private static final String TAG = "TimerActivity";
private static final boolean DEBUG = true;
// ^^ Variable used to log acitivty state
private Handler mHandler;
private Runnable mRunnable;
//private static final long START_TIME_MILLISECONDS = 600000;
// Below start time is for development purposes only
private static long mStartTime = 10000;
private long mTimeRemaining = mStartTime;
private boolean mTimeRunning;
private boolean mBreakTime = false;
private ProgressBar mTimeBar;
private TextView mTime;
private Button mStartPause;
private Button mSetTime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
if(DEBUG) Log.d(TAG, "+ onCreate() +");
mHandler = new Handler();
mTimeBar = findViewById(R.id.time_bar);
mTime = findViewById(R.id.text_view_time);
mStartPause = findViewById(R.id.button_start_pause);
mSetTime = findViewById(R.id.button_set_time);
updateCountDownText();
mTimeBar.setMax((int) mTimeRemaining);
mSetTime.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//FragmentManager manager = getSupportFragmentManager();
DialogFragment setTime = new TimeDialogFragment();
setTime.show(getFragmentManager(),"SET_TIME_DIALOG");
}
});
mStartPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(mTimeRunning){
//pauseTimer();
mTimeRunning = false;
mStartPause.setText("Start");
mHandler.removeCallbacks(mRunnable);
}else{
//startTimer();
timer();
}
}
});
}
// Using a handler + anon runnable
private void timer(){
mRunnable = new Runnable() {
#Override
public void run() {
mTimeRunning = true;
mStartPause.setText("Pause");
mTimeRemaining = mTimeRemaining - 1000;
updateCountDownText();
mTimeBar.incrementProgressBy(1000);
if(mTimeRemaining > 0) {
mHandler.postDelayed(this, 1000);
}else{
// if breaktime is false
if(!mBreakTime) {
DialogFragment dialog = new TimeFinishDialogFragment();
dialog.show(getFragmentManager(),"TIME_FINISH_DIALOG");
mTimeRunning = false;
}else{
// launch break time up dialog.
mBreakTime = false;
DialogFragment dialog = new BreakFinishDialogFragment();
dialog.show(getFragmentManager(), "BREAK_FINSIH_DIALOG");
}
}
}
};
mHandler.postDelayed(mRunnable,1000);
}
public void updateCountDownText(){
int min = (int) (mTimeRemaining / 1000) / 60;
int sec = (int) (mTimeRemaining / 1000) % 60;
String formattedString = String.format(Locale.getDefault(), "%02d:%02d", min, sec);
mTime.setText(formattedString);
}
public void setCountDownText(long time){
int min = (int) (time / 1000) / 60;
int sec = (int) (time / 1000) % 60;
String formattedString = String.format(Locale.getDefault(), "%02d:%02d", min, sec);
mTime.setText(formattedString);
}
#Override
public void userTime(int minutes) {
TimerActivity.mStartTime = (minutes * 60) * 1000;
mTimeRemaining = TimerActivity.mStartTime;
mTimeBar.setMax((int) mTimeRemaining);
setCountDownText(mTimeRemaining);
}
#Override
public void sendResponse(int val) {
if(val == -1){
mTimeRemaining = TimerActivity.mStartTime;
mTimeBar.setMax((int) mTimeRemaining);
updateCountDownText();
mTimeBar.setProgress(0);
mStartPause.setText("Start");
}else if(val == 1) {
mBreakTime = true;
mTimeRemaining = 15000;
mTimeBar.setMax((int) mTimeRemaining);
setCountDownText(mTimeRemaining);
mTimeBar.setProgress(0);
mStartPause.setVisibility(View.INVISIBLE);
timer();
}else {
mTimeRemaining = TimerActivity.mStartTime;
mTimeBar.setMax((int) mTimeRemaining);
updateCountDownText();
mTimeBar.setProgress(0);
timer();
}
}
#Override
public void userResponse(int val) {
if(val < 0) {
// user clicked cance
mTimeRemaining = TimerActivity.mStartTime;
mTimeBar.setMax((int) mTimeRemaining);
updateCountDownText();
mTimeBar.setProgress(0);
mStartPause.setText("Start");
}else {
mTimeRemaining = TimerActivity.mStartTime;
mTimeBar.setMax((int) mTimeRemaining);
updateCountDownText();
mTimeBar.setProgress(0);
timer();
}
mStartPause.setVisibility(View.VISIBLE);
}
TimeFinishedDialog.java
public class TimeFinishDialogFragment extends DialogFragment implements View.OnClickListener{
private Button mCancel;
private Button mSkip;
private Button mStartBreak;
private sendResponse mResponse;
interface sendResponse{
void sendResponse(int val);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//return super.onCreateDialog(savedInstanceState);
View view = LayoutInflater.from(getActivity()).inflate(R.layout.time_finish_dialog_fragment, null, false);
mCancel = view.findViewById(R.id.button_cancel);
mSkip = view.findViewById(R.id.button_skip);
mStartBreak = view.findViewById(R.id.button_start_break);
mCancel.setOnClickListener(this);
mSkip.setOnClickListener(this);
mStartBreak.setOnClickListener(this);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view)
.setTitle("Start Break?");
AlertDialog dialog = builder.create();
dialog.setContentView(view);
return dialog;
}
#Override
public void onClick(View view) {
switch(view.getId()){
case R.id.button_cancel:
mResponse.sendResponse(-1);
getDialog().dismiss();
break;
case R.id.button_skip:
mResponse.sendResponse(0);
getDialog().dismiss();
break;
case R.id.button_start_break:
mResponse.sendResponse(1);
getDialog().dismiss();
break;
default:
break;
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
mResponse = (sendResponse) getActivity();
}catch (ClassCastException e){
System.out.println("Error: " + e);
}
}
}
when the time is up and the app is NOT in the foreground the dialog is still launched
You should not be doing this since this will interrupt the user from doing other work which they might be doing at that time and this can be irritating.
What can I possibly do so that the dialog is launched when the app is not in the foreground?
You can show the dialog only the user is actively using your application or you can fall back to show a notification when the user is not using the app.
And if you desperately want to show a dialog, you can try a dialog themed activity
When I pause the timer and then start it again it seems like the timer counts the current second again. For example it is 00:10, after half a second I stop the timer and when I start it again instead of going from 00:10 to 00:09 in half a second it counts a full second. I can't find what is wrong. Thanks for any help.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer_2);
//...
Timer buttonTimer = new Timer();
buttonTimer.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
if (timer_2_up_running) {
pausetimer_2_up();
starttimer_2_down();
} else {
starttimer_2_up();
if (timer_2_down_running) {
pausetimer_2_down();
private void starttimer_2_up() {
timer_2_up_countdowntimer = new CountDownTimer(starttimeup, 1000) {
#Override
public void onTick(long millisUntilFinished) {
starttimeup = millisUntilFinished;
update_up_text();
#Override
public void onFinish() {
timer_2_up_running = false;
}
}.start();
timer_2_up_running = true;
}
private void starttimer_2_down() {
timer_2_down_countdowntimer = new CountDownTimer(starttimedown, 1000) {
#Override
public void onTick(long millisUntilFinished) {
starttimedown = millisUntilFinished;
update_down_text();
}
#Override
public void onFinish() {
timer_2_down_running = false;
}
}.start();
timer_2_down_running = true;
}
private void pausetimer_2_up() {
timer_2_up_countdowntimer.cancel();
timer_2_up_running = false;
}
private void pausetimer_2_down() {
timer_2_down_countdowntimer.cancel();
timer_2_down_running = false;
}
private void update_up_text() {
int minutes_up = (int) (starttimeup / 1000) / 60;
int seconds_up = (int) (starttimeup / 1000) % 60;
String time_2_up_left_formatted = String.format(Locale.getDefault(), "%02d:%02d", minutes_up, seconds_up);
timer_2_up.setText(time_2_up_left_formatted);
}
private void update_down_text() {
int minutes_down = (int) (starttimedown / 1000) / 60;
int seconds_down = (int) (starttimedown / 1000) % 60;
String time_2_down_left_formatted = String.format(Locale.getDefault(), "%02d:%02d", minutes_down, seconds_down);
timer_2_down.setText(time_2_down_left_formatted);
}
You can use Chronometer to display recording time. start the
Chronometer when recording start and stop it when recording stop
<Chronometer
android:id="#+id/chronometerRecordTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/relativeLayout_bottom_video_controls"
android:layout_centerInParent="true"
android:layout_marginBottom="20dp"
android:visibility="invisible"/>
private Chronometer chronometerRecordTime;
chronometerRecordTime = findViewById(R.id.chronometerRecordTime);
chronometerRecordTime.setBase(SystemClock.elapsedRealtime()); // Reset
chronometerRecordTime.start(); // start
chronometerRecordTime.stop(); // stop
I have also crate timer to stop recording after one min. you can
modify it according to your requirement.
int myTimeCounter;
Timer myRecordingTimer;
private boolean myTimerHasStarted = false;
private String TAG = "Log";
private void startTimerTask() {
myTimeCounter = 1;
myRecordingTimer = new Timer();
myRecordingTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
runOnUiThread(new Runnable() {
public void run() {
myTimerHasStarted = true;
if (myTimeCounter == 60) {
myRecordingTimer.cancel();
myTimerHasStarted = false;
return;
}
Log.d(TAG, "timer=" + String.valueOf(myTimeCounter));
myTimeCounter++;
}
});
}
}, 0, 1000);
}
I'm a novice in Java (Less than 3 months experience), and for a project I've been working on I need to create a timer.
I've done this before, however I do not know how to do one thing.
I want to start a timer when a second timer ends. What I mean by this is that instead of using a start/stop button to start a timer, I want to have a second timer (that starts at 3 seconds) determine when the first timer starts. For example, if the first timer is at 30 seconds, it will start counting down when the second timer finishes counting down from 3-0.
I know there has to be other classes or methods/listeners to do this, but as I've stated earlier, it's my first time ever working with Java (I normally use C++).
Any help/guidance/code on how to achieve this would be awesome. Here is the code I was toying around with to try and achieve this.
Java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.os.CountDownTimer;
public class Timer extends AppCompatActivity
{
TextView timer;
TextView timerStart;
Button multi;
int track;
int seconds;
CountDownTimer countDownTimer;
CountDownTimer start;
View.OnClickListener btnListen = new View.OnClickListener(){
#Override
public void onClick(View v)
{
switch(v.getId())
{
case R.id.multi : start();
break;
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
timer = (TextView) findViewById(R.id.timer);
timerStart = (TextView) findViewById(R.id.timerStart);
multi = (Button) findViewById(R.id.multi);
multi.setOnClickListener(btnListen);
multi.setText("Start");
}
public void start_timer()
{
track = 3;
start = new CountDownTimer(3*1000,1000) {
#Override
public void onTick(long millisUntilFinished) {
timerStart.setText("" + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
timerStart.setText("Begin");
track = 0;
}
}.start();
seconds = 30;
if (timerStart.getText().equals("Begin"))
{
start.cancel();
countDownTimer = new CountDownTimer(30 * 1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timer.setText("" + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
timer.setText("BEEP");
}
}.start();
}
else
{
System.out.println("Nothing");
}
}
public void start()
{
start_timer();
/*seconds = 30;
if (timerStart.getText().equals("Begin"))
{
countDownTimer = new CountDownTimer(seconds * 1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timer.setText("" + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
timer.setText("BEEP");
}
}.start();
}*/
}
}
Again, this is just something I'm toying around with. If there is a different way to do this (Like using a Runnable or Handler), then I'm open to it. My goal is to learn Java.
How about this? I modified CountDownTimer to enable to be chained.
public abstract class ChainedCountDownTimer {
/**
* Millis since epoch when alarm should stop.
*/
private final long mMillisInFuture;
/**
* The interval in millis that the user receives callbacks
*/
private final long mCountdownInterval;
private long mStopTimeInFuture;
/**
* boolean representing if the timer was cancelled
*/
private boolean mCancelled = false;
/**
* First timer in chaining
*/
private ChainedCountDownTimer first;
/**
* Next timer
*/
private ChainedCountDownTimer next;
/**
* #param millisInFuture The number of millis in the future from the call
* to {#link #start()} until the countdown is done and {#link #onFinish()}
* is called.
* #param countDownInterval The interval along the way to receive
* {#link #onTick(long)} callbacks.
*/
public ChainedCountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
first = this;
}
/**
* Cancel the countdown.
*/
public synchronized final void cancel() {
first.mCancelled = true;
mHandler.removeMessages(MSG);
}
public void start() {
first.startInternal();
}
/**
* Start the countdown.
*/
public synchronized final ChainedCountDownTimer startInternal() {
mCancelled = false;
if (mMillisInFuture <= 0) {
onFinish();
if (next != null) {
next.startInternal();
}
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
/**
* Callback fired on regular interval.
* #param millisUntilFinished The amount of time until finished.
*/
public abstract void onTick(long millisUntilFinished);
/**
* Callback fired when the time is up.
*/
public abstract void onFinish();
public ChainedCountDownTimer setNext(ChainedCountDownTimer next) {
this.next = next;
next.first = this.first;
return this.next;
}
private static final int MSG = 1;
// handles counting down
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
synchronized (ChainedCountDownTimer.this) {
if (first.mCancelled) {
return;
}
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
onFinish();
if (next != null) {
next.startInternal();
}
} else if (millisLeft < mCountdownInterval) {
// no tick, just delay until done
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);
// take into account user's onTick taking time to execute
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
// special case: user's onTick took more than interval to
// complete, skip to next interval
while (delay < 0) delay += mCountdownInterval;
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};
}
You can use it like this.
ChainedCountDownTimer timer1 = new ChainedCountDownTimer(3 * 1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.d(TAG, "timer1 onTick");
}
#Override
public void onFinish() {
Log.d(TAG, "timer1 onFinish");
}
};
ChainedCountDownTimer timer2 = new ChainedCountDownTimer(30 * 1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.d(TAG, "timer2 onTick");
}
#Override
public void onFinish() {
Log.d(TAG, "timer2 onFinish");
}
};
timer1.setNext(timer2).start();