How to make a countdown timer in Android?

AndroidTimerCountdown

Android Problem Overview


I have two EditTexts in XML. In one EditText, the user can put a number as minutes and in another EditText, a number as seconds. After clicking the finish button, the seconds EditText should start to countdown and update its text every second.

Additionally, how can I keep it updating until it gets to zero minutes and zero seconds?

Android Solutions


Solution 1 - Android

new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
       //here you can have your logic to set text to edittext
    }

    public void onFinish() {
        mTextField.setText("done!");
    }

}.start();

Refer to this link.

Solution 2 - Android

if you use the below code (as mentioned in accepted answer),

new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
       //here you can have your logic to set text to edittext
    }

    public void onFinish() {
        mTextField.setText("done!");
    }

}.start();

It will result in memory leak of the instance of the activity where you use this code, if you don't carefully clean up the references.

use the following code

//Declare timer
CountDownTimer cTimer = null;

//start timer function
void startTimer() {
    cTimer = new CountDownTimer(30000, 1000) {
		public void onTick(long millisUntilFinished) {
		}
		public void onFinish() {
		}
	};
    cTimer.start();
}


//cancel timer
void cancelTimer() {
    if(cTimer!=null)
        cTimer.cancel();
}

You need to call cTtimer.cancel() whenever the onDestroy()/onDestroyView() in the owning Activity/Fragment is called.

Solution 3 - Android

enter image description here

MainActivity.java

package com.zeustechnocrats.countdown;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    private String EVENT_DATE_TIME = "2023-12-31 10:30:00";
    private String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private LinearLayout linear_layout_1, linear_layout_2;
    private TextView tv_days, tv_hour, tv_minute, tv_second;
    private Handler handler = new Handler();
    private Runnable runnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.count_down);

        initUI();
        countDownStart();
    }

    private void initUI() {
        linear_layout_1 = findViewById(R.id.linear_layout_1);
        linear_layout_2 = findViewById(R.id.linear_layout_2);
        tv_days = findViewById(R.id.tv_days);
        tv_hour = findViewById(R.id.tv_hour);
        tv_minute = findViewById(R.id.tv_minute);
        tv_second = findViewById(R.id.tv_second);
    }

    private void countDownStart() {
        runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    handler.postDelayed(this, 1000);
                    SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
                    Date event_date = dateFormat.parse(EVENT_DATE_TIME);
                    Date current_date = new Date();
                    if (!current_date.after(event_date)) {
                        long diff = event_date.getTime() - current_date.getTime();
                        long Days = diff / (24 * 60 * 60 * 1000);
                        long Hours = diff / (60 * 60 * 1000) % 24;
                        long Minutes = diff / (60 * 1000) % 60;
                        long Seconds = diff / 1000 % 60;
                        //
                        tv_days.setText(String.format("%02d", Days));
                        tv_hour.setText(String.format("%02d", Hours));
                        tv_minute.setText(String.format("%02d", Minutes));
                        tv_second.setText(String.format("%02d", Seconds));
                    } else {
                        linear_layout_1.setVisibility(View.VISIBLE);
                        linear_layout_2.setVisibility(View.GONE);
                        handler.removeCallbacks(runnable);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        handler.postDelayed(runnable, 0);
    }

    protected void onStop() {
        super.onStop();
        handler.removeCallbacks(runnable);
    }
}

activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="horizontal">

    <LinearLayout
        android:id="@+id/linear_layout_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/black"
        android:gravity="center_horizontal"
        android:visibility="gone">

        <TextView
            android:id="@+id/tv_event"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="20dp"
            android:text="Android Event Start"
            android:textColor="@android:color/white"
            android:textSize="20dp"
            android:textStyle="normal" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/linear_layout_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/black"
        android:visibility="visible">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_days"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="00"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/tv_days_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="Days"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="normal" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_hour"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="00"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/tv_hour_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="Hour"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="normal" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_minute"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="00"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/tv_minute_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="Minute"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="normal" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_second"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="00"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/tv_second_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="Second"
                android:textColor="@android:color/white"
                android:textSize="20dp"
                android:textStyle="normal" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

Solution 4 - Android

just copy paste the following code........

MainActivity

package com.example.countdowntimer;

import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.widget.TextView;


public class MainActivity extends Activity {


      TextView text1;

 private static final String FORMAT = "%02d:%02d:%02d";

 int seconds , minutes;

@Override
public void onCreate(Bundle savedInstanceState) {

	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
	
	
	text1=(TextView)findViewById(R.id.textView1);
		
	new CountDownTimer(16069000, 1000) { // adjust the milli seconds here

	    public void onTick(long millisUntilFinished) {
	    			    	
	    	text1.setText(""+String.format(FORMAT,
	                TimeUnit.MILLISECONDS.toHours(millisUntilFinished),
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(
	                TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
  TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(
	                  TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished))));				
	    }

	    public void onFinish() {
	    	text1.setText("done!");
	    }
	 }.start();				
	 
  }

  }

activity_main.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_marginLeft="34dp"
    android:layout_marginTop="58dp"
    android:text="Large Text"
    android:textAppearance="?android:attr/textAppearanceMedium" />

   </RelativeLayout>

Solution 5 - Android

Just Call below function by passing seconds and textview object

public void reverseTimer(int Seconds,final TextView tv){
	
	new CountDownTimer(Seconds* 1000+1000, 1000) {

		public void onTick(long millisUntilFinished) {
			int seconds = (int) (millisUntilFinished / 1000);
			int minutes = seconds / 60;
			seconds = seconds % 60;
			tv.setText("TIME : " + String.format("%02d", minutes)
					+ ":" + String.format("%02d", seconds));
		}

		public void onFinish() {
			tv.setText("Completed");
		}
	}.start();
}

Solution 6 - Android

Revers CountDown timer with hours minutes and seconds

public void reverseTimer(int Seconds, final TextView tv) {

    new CountDownTimer(Seconds * 1000 + 1000, 1000) {

        public void onTick(long millisUntilFinished) {
            int seconds = (int) (millisUntilFinished / 1000);

            int hours = seconds / (60 * 60);
            int tempMint = (seconds - (hours * 60 * 60));
            int minutes = tempMint / 60;
            seconds = tempMint - (minutes * 60);

            tv.setText("TIME : " + String.format("%02d", hours)
                    + ":" + String.format("%02d", minutes)
                    + ":" + String.format("%02d", seconds));
        }

        public void onFinish() {
            tv.setText("Completed");
        }
    }.start();
}

Solution 7 - Android

Using Kotlin:

var timer = object: CountDownTimer(30000, 1000) {
        override fun onTick(millisUntilFinished: Long) {
            tvTimer.setText("seconds remaining: " + millisUntilFinished / 1000)
        }

        override fun onFinish() {
            tvTimer.setText("done!")
        }
    }
timer.start()

Solution 8 - Android

Output: 01:30

new CountDownTimer(90000, 1000) {

            public void onTick(long duration) {
                //tTimer.setText("seconds remaining: " + millisUntilFinished / 1000);
                //here you can have your logic to set text to edittext resource id
                // Duration
                long Mmin = (duration / 1000) / 60;
                long Ssec = (duration / 1000) % 60;
                if (Ssec < 10) {
                    tTimer.setText("" + Mmin + ":0" + Ssec);
                } else tTimer.setText("" + Mmin + ":" + Ssec);
            }

            public void onFinish() {
                tTimer.setText("00:00");
            }

        }.start();

Solution 9 - Android

    var futureMinDate = Date()
    val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
    try {
        futureMinDate = sdf.parse("2019-08-22")
    } catch (e: ParseException) {
        e.printStackTrace()
    }
    
    // Here futureMinDate.time Returns the number of milliseconds since January 1, 1970, 00:00:00 GM
    // So we need to subtract the millis from current millis to get actual millis
    object : CountDownTimer(futureMinDate.time - System.currentTimeMillis(), 1000) {
        override fun onTick(millisUntilFinished: Long) {
            val sec = (millisUntilFinished / 1000) % 60
            val min = (millisUntilFinished / (1000 * 60)) % 60
            val hr = (millisUntilFinished / (1000 * 60 * 60)) % 24
            val day = ((millisUntilFinished / (1000 * 60 * 60)) / 24).toInt()
            val formattedTimeStr = if (day > 1) "$day days $hr : $min : $sec"
            else "$day day $hr : $min : $sec"
            tvFlashDealCountDownTime.text = formattedTimeStr
        }

        override fun onFinish() {
            tvFlashDealCountDownTime.text = "Done!"
        }
    }.start()

Pass a future date and convert it to millisecond.

It will work like a charm.

Solution 10 - Android

The Interface way.

import android.os.CountDownTimer;

/**
 * Created by saikiran on 07-03-2016.
 */
public class CountDownTimerCustom extends CountDownTimer {

    private TimeTickListener mTickListener;
    private TimeFinishListener mFinishListener;
    private long millisUntilFinished;

    public CountDownTimerCustom(long millisInFuture, long countDownInterval) {
        super(millisInFuture, countDownInterval);

    }

    public void updateTickAndFinishListener(TimeTickListener tickListener) {
        mTickListener = tickListener;
    }

    public void updateFinishListner(TimeFinishListener listener) {
        mFinishListener = listener;
    }

    public long getCurrentMs() {
        return millisUntilFinished;
    }

    public int getCurrentSec() {
        return (int) millisUntilFinished / 1000;
    }

    @Override
    public void onTick(long millisUntilFinished) {
        this.millisUntilFinished = millisUntilFinished;
        if (mTickListener != null)
            mTickListener.onTick(millisUntilFinished);
    }

    @Override
    public void onFinish() {
        if (mTickListener != null)
            mTickListener.onFinished();
        mFinishListener.onFinished();
    }


    public interface TimeTickListener {
        void onTick(long mMillisUntilFinished);

        void onFinished();
    }

    public interface TimeFinishListener {
        void onFinished();
    }
}

Solution 11 - Android

Here's the solution I used in Kotlin

private fun startTimer()
{
    Log.d(TAG, ":startTimer: timeString = '$timeString'")

    object : CountDownTimer(TASK_SWITCH_TIMER, 250)
    {
        override fun onTick(millisUntilFinished: Long)
        {
            val secondsUntilFinished : Long = 
            Math.ceil(millisUntilFinished.toDouble()/1000).toLong()
            val timeString = "${TimeUnit.SECONDS.toMinutes(secondsUntilFinished)}:" +
                    "%02d".format(TimeUnit.SECONDS.toSeconds(secondsUntilFinished))
            Log.d(TAG, ":startTimer::CountDownTimer:millisUntilFinished = $ttlseconds")
            Log.d(TAG, ":startTimer::CountDownTimer:millisUntilFinished = $millisUntilFinished")
        }

        @SuppressLint("SetTextI18n")
        override fun onFinish()
        {
            timerTxtVw.text = "0:00"
            gameStartEndVisibility(true)
        }
    }.start()
}

Solution 12 - Android

public class Scan extends AppCompatActivity {
int minute;
long min;
TextView tv_timer;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_scan2);
    tv_timer=findViewById(R.id.tv_timer);
    minute=Integer.parseInt("Your time in string form like 10");
    min= minute*60*1000;
    counter(min);
}
private void counter(long min) {
    CountDownTimer timer = new CountDownTimer(min, 1000) {
        public void onTick(long millisUntilFinished) {
            int seconds = (int) (millisUntilFinished / 1000) % 60;
            int minutes = (int) ((millisUntilFinished / (1000 * 60)) % 60);
            int hours = (int) ((millisUntilFinished / (1000 * 60 * 60)) % 24);
            tv_timer.setText(String.format("%d:%d:%d", hours, minutes, seconds));
        }
        public void onFinish() {
            Toast.makeText(getApplicationContext(), "Your time has been completed",
                    Toast.LENGTH_LONG).show();
        }
    };
    timer.start();
}

}

Solution 13 - Android

Try this way:

private void startTimer() {
    startTimer = new CountDownTimer(30000, 1000) {

        public void onTick(long millisUntilFinished) {

            long sec = (TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) -
 TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)));

            Log.e(TAG, "onTick: "+sec );
            tv_timer.setText(String.format("( %02d SEC )", sec));
            if(sec == 1)
            {

                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        tv_timer.setText("( 00 SEC )");
                    }
                }, 1000);
            }


        }

        public void onFinish() {
            tv_timer.setText("Timer finish");
        }
    }.start();
}

Solution 14 - Android

// the count down timer


 new  CountDownTimer(30000, 1000)
         {
        @Override
        public void onTick(long l) {

        }
        @Override
        public void onFinish() {
        
                //on finish the count down timer finsih        
                         }
          
            }
        }

    }.start();

Solution 15 - Android

I achieve a cool approach for the timer with kotlin flows so you can implement this in ViewModel

    var countDownInit = 30
    fun countDownTimer() = flow<Int> {
    var time = countDownInit
    emit(time)
    while (true){
        time--
        delay(1000L)
        countDownInit = time
        emit(time)
    }
}

then in your activity or fragment just call this function like this

lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
                 viewModel.countDownTimer().collect{time->
                      //and update UI 
                     //and for the finish section you can just use this
                     this.cancel()          
                 }
        }
}

And there is now crash or sth on the pause of the application lifecycle and always you have the latest seconds

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSabbir AhmedView Question on Stackoverflow
Solution 1 - AndroidShankar AgarwalView Answer on Stackoverflow
Solution 2 - AndroidshanraisshanView Answer on Stackoverflow
Solution 3 - AndroidSanjay MangaroliyaView Answer on Stackoverflow
Solution 4 - AndroidgAuRaV jAiNView Answer on Stackoverflow
Solution 5 - AndroidPrashant Maheshwari AndroView Answer on Stackoverflow
Solution 6 - Androidtej shahView Answer on Stackoverflow
Solution 7 - AndroidDaniel ShterenbergView Answer on Stackoverflow
Solution 8 - AndroidVikash SharmaView Answer on Stackoverflow
Solution 9 - AndroidShaonView Answer on Stackoverflow
Solution 10 - AndroidSaiView Answer on Stackoverflow
Solution 11 - AndroiddeepGraveView Answer on Stackoverflow
Solution 12 - AndroidParamatma SharanView Answer on Stackoverflow
Solution 13 - AndroidVishal YadavView Answer on Stackoverflow
Solution 14 - AndroidMazhar IqbalView Answer on Stackoverflow
Solution 15 - Androidmmdreza baqalpourView Answer on Stackoverflow