如何在Android中制作倒数计时器?
Posted
技术标签:
【中文标题】如何在Android中制作倒数计时器?【英文标题】:How to make a countdown timer in Android? 【发布时间】:2012-04-19 09:27:03 【问题描述】:我在 XML 中有两个 EditText。在一个 EditText 中,用户可以输入一个数字为分钟,而在另一个 EditText 中,一个数字为秒。单击完成按钮后,EditText 的秒数应该开始倒计时并每秒更新其文本。
另外,我怎样才能让它保持更新,直到它达到零分零秒?
【问题讨论】:
android countdown 的可能重复项 【参考方案1】: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();
请参阅此link。
【讨论】:
这是一个不错的答案,但谁能告诉我如何自定义设置倒计时时间,而不仅仅是输入 30 秒?我尝试从 EditText 获取值,但它似乎根本不起作用。 如果我想将 CountDownTimer 建立在设定的闹钟上怎么办?我怎么知道有多少 milisUntilFinished? 不知道countdowntimer
有没有暂停方法?假设用户想暂停游戏,他们点击了一个按钮,倒数计时器暂停,当他们点击播放时,它一直在滴答作响?
你检查链接了吗?
如果我想让文本达到十秒时使文本变为红色,并在达到五秒时使文本闪烁怎么办?非常感谢老兄!【参考方案2】:
如果您使用以下代码(如已接受的答案中所述),
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();
如果不仔细清理引用,将导致使用此代码的活动实例的内存泄漏。
使用下面的代码
//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();
每当调用所属 Activity/Fragment 中的 onDestroy()/onDestroyView() 时,您都需要调用 cTtimer.cancel()。
【讨论】:
是的! 10/10。这应该是正确的答案。或者,即使您按 BACK,countDownThread 也非常有效。你可以放置一个 Log.i,如果你不放置“.cancel()”,你会看到它每 1 秒抛出一次信息。 有没有办法在取消之前检查 CountDownTiner 是否仍在运行? 检查计时器是否为 !=null【参考方案3】: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_
android:layout_
android:background="@android:color/white"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/linear_layout_1"
android:layout_
android:layout_
android:background="@android:color/black"
android:gravity="center_horizontal"
android:visibility="gone">
<TextView
android:id="@+id/tv_event"
android:layout_
android:layout_
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_
android:layout_
android:background="@android:color/black"
android:visibility="visible">
<LinearLayout
android:layout_
android:layout_
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_days"
android:layout_
android:layout_
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_
android:layout_
android:layout_gravity="center"
android:text="Days"
android:textColor="@android:color/white"
android:textSize="20dp"
android:textStyle="normal" />
</LinearLayout>
<LinearLayout
android:layout_
android:layout_
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_hour"
android:layout_
android:layout_
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_
android:layout_
android:layout_gravity="center"
android:text="Hour"
android:textColor="@android:color/white"
android:textSize="20dp"
android:textStyle="normal" />
</LinearLayout>
<LinearLayout
android:layout_
android:layout_
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_minute"
android:layout_
android:layout_
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_
android:layout_
android:layout_gravity="center"
android:text="Minute"
android:textColor="@android:color/white"
android:textSize="20dp"
android:textStyle="normal" />
</LinearLayout>
<LinearLayout
android:layout_
android:layout_
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_second"
android:layout_
android:layout_
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_
android:layout_
android:layout_gravity="center"
android:text="Second"
android:textColor="@android:color/white"
android:textSize="20dp"
android:textStyle="normal" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
【讨论】:
为什么是handler.postDelayed(runnable, 1 * 1000);
??
一旦活动被销毁,不要忘记清理计时器。否则你会发送内存泄漏
handler.postDelayed(runnable, 0) = handler.post(runnable)
如果有人想添加时区,可以试试这个 dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+05:30"));【参考方案4】:
只需复制粘贴以下代码........
MainActivity
包 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_
android:layout_
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_
android:layout_
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>
【讨论】:
但是当我的手机锁定时它暂停并且当我解锁它会恢复..我可以为继续计时器做什么?? 请不要鼓励复制粘贴代码。一个文档和解释的链接会是一个更好的答案。【参考方案5】:只需通过传递秒数和 textview 对象调用下面的函数
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();
【讨论】:
捕捉 NPE 的完美案例。当 Activity 被销毁并且计时器保持运行时会发生什么?【参考方案6】:倒计时计时器以小时分钟和秒为单位
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();
【讨论】:
【参考方案7】:使用 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()
【讨论】:
【参考方案8】:输出: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();
【讨论】:
【参考方案9】:接口方式。
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();
【讨论】:
如果可以为初学者提供更多代码:) @shareef 你好,你在找什么? 我的意思是 gist 或 repo 的使用会很棒【参考方案10】:这是我在 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()
【讨论】:
【参考方案11】: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();
【讨论】:
【参考方案12】: 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()
传递一个未来日期并将其转换为毫秒。
它会像一个魅力。
【讨论】:
【参考方案13】:试试这个方法:
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();
【讨论】:
【参考方案14】:// 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();
【讨论】:
【参考方案15】:我使用 kotlin 流实现了一个很酷的计时器方法,因此您可以在 ViewModel
中实现它 var countDownInit = 30
fun countDownTimer() = flow<Int>
var time = countDownInit
emit(time)
while (true)
time--
delay(1000L)
countDownInit = time
emit(time)
然后在您的活动或片段中,只需像这样调用此函数
lifecycleScope.launch
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED)
viewModel.countDownTimer().collecttime->
//and update UI
//and for the finish section you can just use this
this.cancel()
现在在应用程序生命周期暂停时会出现崩溃或某事,并且您始终拥有最新的秒数
【讨论】:
以上是关于如何在Android中制作倒数计时器?的主要内容,如果未能解决你的问题,请参考以下文章