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.
Related
How to make this action happen at the end of the time when there are still 5 seconds left.
This is the code of the action that I want to do when there are 5 seconds left from the timer:
mTextViewCountDown.setTextColor(Color.RED);
zooming_second = AnimationUtils.loadAnimation(Level1.this, R.anim.watch_zoo);
mTextViewCountDown.startAnimation(zooming_second);
soundPlay(watch);
In this method:
//variable start
private static final long START_TIME_IN_MILLIS = 60000;
private TextView mTextViewCountDown;
private CountDownTimer mCountDownTimer;
private boolean mTimerRunning;
private long mTimeLeftInMillis = START_TIME_IN_MILLIS;
//variable end
private void startTimer() {
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.ENGLISH, "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
mTimerRunning = true;
}
#Override
public void onFinish() {
mTimerRunning = false;
TimeOutDialog();
soundPlay(time_out_sound);
mediaPlayer1.stop();
tadam_false.stop();
tadam_true.stop();
}
}.start();
}
private void pauseTimer () {
mCountDownTimer.cancel();
mTimerRunning = false;
}
Inside onTick(long) method simply check how many seconds are left. And if it is five, trigger your action.
EDIT
My approach to hitting the right time would be something like this:
if (Math.abs(mTimeLeftInMillis - 5000) < 100) {
// start the animation
}
This would avoid issues with if (mTimeLeftInMillis == 5000) as it gives it some buffer. It's needed because it will not trigger at exactly 5000 milliseconds.
Thanks! I did it like this:
if (mTimeLeftInMillis <= 6000){
mTextViewCountDown.setTextColor(Color.RED);
zooming_second = AnimationUtils.loadAnimation(Level1.this,
R.anim.watch_zoo);
mTextViewCountDown.startAnimation(zooming_second);
soundPlay(watch);
}
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 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.
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 have an app that has one countdown timer that should show up the same for every user when they open the app. In order to do this, I have based the time that the users' phones show on Epoch time. I do the following calculations to (what I thought would...) ensure that each phone shows the same time, and that the countdown clock is continuous and accurate. However, every time I open the app up, the clock is at a totally different time, when I think it should be continuously counting down and resetting. What's wrong? I have included my code below:
private static final int COUNTDOWN_DURATION = 30; //time in seconds
private static final long BASE_TIME = 1470729402L; //an arbitrary Epoch time that I have picked as a reference point
private TextView tvTimer;
private Long currentTimeMillis;
private int finalTime;
private boolean firstTime;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
//set up basics
...
//set up timer
tvTimer = (TextView) findViewById(R.id.tvTimer);
firstTime = true;
setCurrentTime();
}
private void setCurrentTime() {
currentTimeMillis = System.currentTimeMillis();
long currentTimeSecs = currentTimeMillis/1000;
long timeDiff = currentTimeSecs - BASE_TIME;
//determines what spot the countdown timer is at when the app is started
finalTime = (int) (timeDiff % COUNTDOWN_DURATION);
resetTimer();
}
public void resetTimer(){
if (firstTime) {
CountDownTimer countDownTimer = new CountDownTimer(finalTime * 1000, 1000) {
public void onTick(long millisUntilFinished) {
tvTimer.setText(" " + millisUntilFinished / 1000 + " ");
}
public void onFinish() {
resetTimer();
}
};
countDownTimer.start();
firstTime = false;
}
else {
CountDownTimer countDownTimer = new CountDownTimer(COUNTDOWN_DURATION * 1000, 1000) {
public void onTick(long millisUntilFinished) {
tvTimer.setText(" " + millisUntilFinished / 1000 + " ");
}
public void onFinish() {
resetTimer();
}
};
countDownTimer.start();
}
}