Android中CountDownTimer顺序执行及循环轮次实现方案问询
解决Android CountDownTimer顺序执行及轮次重复问题
问题根源
你用while循环的方式完全错误,因为CountDownTimer是异步执行的,主线程的while会持续阻塞UI线程,而且异步更新的状态变量无法被while实时感知,自然没法保证时序正确。
可行方案:利用回调链式启动
核心逻辑是在前一个计时器的onFinish()回调里启动下一个计时器,同时维护轮次计数,控制最后一轮是否跳过休息阶段。
以下是完整的实现代码:
package com.example.empty_tv_test; import android.os.Bundle; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import android.os.CountDownTimer; import android.widget.TextView; import java.text.DecimalFormat; import java.text.NumberFormat; public class MainActivity extends AppCompatActivity { private TextView textView; // 配置参数:可根据需求修改 private static final int TOTAL_ROUNDS = 3; // 总轮次 private static final long PREPARE_DURATION = 3000; // 预备倒计时时长(3秒) private static final long MAIN_DURATION = 7000; // 主计时时长(7秒) private static final long REST_DURATION = 8000; // 休息时长(8秒) private int currentRound = 0; // 当前执行的轮次 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); textView = findViewById(R.id.textViewTimer); // 启动第一轮的预备计时 startPrepareTimer(); } // 启动预备倒计时 private void startPrepareTimer() { new CountDownTimer(PREPARE_DURATION, 1000) { @Override public void onTick(long millisUntilFinished) { updateTimerText(millisUntilFinished); } @Override public void onFinish() { textView.setText("开始主计时"); // 预备结束,启动主计时 startMainTimer(); } }.start(); } // 启动主计时器 private void startMainTimer() { currentRound++; new CountDownTimer(MAIN_DURATION, 1000) { @Override public void onTick(long millisUntilFinished) { updateTimerText(millisUntilFinished); } @Override public void onFinish() { textView.setText("主计时结束"); // 判断是否是最后一轮 if (currentRound < TOTAL_ROUNDS) { // 非最后一轮,启动休息计时 startRestTimer(); } else { // 最后一轮,结束整个流程 textView.setText("所有轮次完成"); } } }.start(); } // 启动休息计时器 private void startRestTimer() { new CountDownTimer(REST_DURATION, 1000) { @Override public void onTick(long millisUntilFinished) { updateTimerText(millisUntilFinished); } @Override public void onFinish() { textView.setText("休息结束,进入下一轮"); // 休息结束,启动下一轮的预备计时 startPrepareTimer(); } }.start(); } // 统一更新计时器文本 private void updateTimerText(long millisUntilFinished) { NumberFormat f = new DecimalFormat("00"); long hour = (millisUntilFinished / 3600000) % 24; long min = (millisUntilFinished / 60000) % 60; long sec = (millisUntilFinished / 1000) % 60; textView.setText(f.format(hour) + ":" + f.format(min) + ":" + f.format(sec)); } }
关键说明
- 链式启动:每个计时器的
onFinish()负责启动下一个阶段,完全保证时序顺序,不会出现并行执行的问题 - 轮次控制:用
currentRound跟踪当前轮次,主计时结束后判断是否需要启动休息阶段 - 代码解耦:把三个阶段拆分为独立方法,逻辑清晰,便于后续修改各阶段的行为或时长
- 主线程安全:
CountDownTimer的回调默认在主线程执行,直接更新UI不会有问题
内容的提问来源于stack exchange,提问作者Darky
相关产品推荐
相关产品推荐

