【问题标题】:How to make a countdown timer in Android?如何在Android中制作倒数计时器?
【发布时间】:2012-04-19 09:27:03
【问题描述】:

我在 XML 中有两个 EditText。在一个 EditText 中,用户可以输入一个数字为分钟,而在另一个 EditText 中,一个数字为秒。单击完成按钮后,EditText 的秒数应该开始倒计时并每秒更新其文本。

另外,我怎样才能让它保持更新,直到它达到零分零秒?

【问题讨论】:

标签: android timer 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_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>

【讨论】:

  • 为什么是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_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>

【讨论】:

  • 但是当我的手机锁定时它暂停并且当我解锁它会恢复..我可以为继续计时器做什么??
  • 请不要鼓励复制粘贴代码。一个文档和解释的链接会是一个更好的答案。
【解决方案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().collect{time->
                                        //and update UI 
                                       //and for the finish section you can just use this
                                       this.cancel()          
                                   }
                          }
                  }
                  

                  现在在应用程序生命周期暂停时会出现崩溃或某事,并且您始终拥有最新的秒数

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多