如何在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中制作倒数计时器?的主要内容,如果未能解决你的问题,请参考以下文章

Android游戏中的倒数计时器

如何从 Android 应用程序与服务器同步倒数计时器

如何通过在倒数计时器中按住按钮来添加值

圆形进度条 Android

用 Python 和 Tkinter 制作倒数计时器?

如何创建一个倒数计时器,当屏幕关闭时停止并“等待”,重新打开时恢复。安卓