Android开发:获取NumberPicker值传入CountDownTimer实现启停倒计时功能
问题原因分析
- 空指针隐患+时长无法更新:你把
t1、t2定义为全局final变量,类初始化的时候np1、np2还没绑定布局,仍是null,调用getValue()会直接触发空指针崩溃。同时final修饰后值不可修改,后续用户调整NumberPicker的数值,倒计时时长也不会同步更新。 - 时间单位错误:
t2的计算只乘了60,得到的是秒值,而CountDownTimer要求传入毫秒单位,需要额外乘1000,否则实际时长只有预期的千分之一。 - 倒计时初始化时机错误:你在
onCreate里就初始化了CountDownTimer,用的是初始固定值,后续用户调整选择器数值后,倒计时时长还是初始值,不会同步更新。 - 重复启动冲突:如果当前倒计时已经在运行,再次点击启动按钮会触发多个倒计时同时运行,导致显示混乱。
修复方案
调整逻辑,每次点击启动按钮的时候,再实时获取当前NumberPicker的选中值,动态创建CountDownTimer即可,修复后的完整代码如下:
public class TimeManager extends AppCompatActivity { private NumberPicker np1 = null; private NumberPicker np2 = null; private Button bt1 = null; private Button bt2 = null; private Button bt3 = null; private TextView tv = null; private CountDownTimer cdt; @RequiresApi(api = Build.VERSION_CODES.Q) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_time_manager); np1 = findViewById(R.id.numPicker); np2 = findViewById(R.id.numPicker2); bt1 = findViewById(R.id.button2); bt2 = findViewById(R.id.button4); bt3 = findViewById(R.id.button5); tv = findViewById(R.id.textView4); bt1.setOnClickListener(btlis1); bt2.setOnClickListener(btlis2); bt3.setOnClickListener(btlis3); np1.setMinValue(0); //設定最小值 np1.setMaxValue(23); //設定最大值 np1.setValue(1); //設定現值 np1.setWrapSelectorWheel(true); np1.setTextSize(60f); np2.setMinValue(0); //設定最小值 np2.setMaxValue(59); //設定最大值 np2.setValue(1); //設定現值 np2.setWrapSelectorWheel(true); np2.setTextSize(60f); } View.OnClickListener btlis1 = new View.OnClickListener() { @Override public void onClick(View v) { Intent it = new Intent(TimeManager.this, Home.class); startActivity(it); } }; View.OnClickListener btlis2 = new View.OnClickListener() { @Override public void onClick(View v) { // 每次启动前先取消之前的倒计时,避免冲突 if (cdt != null) { cdt.cancel(); } // 实时获取当前选中的时长,转成毫秒 long totalTime = np1.getValue() * 3600 * 1000L + np2.getValue() * 60 * 1000L; // 动态创建倒计时 cdt = new CountDownTimer(totalTime, 1000) { @Override public void onTick(long millisUntilFinished) { long t3 = millisUntilFinished / 1000; tv.setEnabled(false); tv.setText(t3 + "秒"); } @Override public void onFinish() { tv.setEnabled(true); tv.setText("重新发送"); } }; cdt.start(); } }; View.OnClickListener btlis3 = new View.OnClickListener() { @Override public void onClick(View v) { if (cdt != null) { cdt.cancel(); // 取消后恢复文字状态,可根据需求调整 tv.setEnabled(true); tv.setText("已取消"); } } }; }
补充说明
- 删掉了无用的NumberPicker监听代码,不需要实时监听数值变化,启动时取一次当前值就足够
- 新增了非空判断,避免cdt为空的时候调用
cancel/start触发空指针 - 修复了时间单位的计算错误,确保总时长符合预期
内容的提问来源于stack exchange,提问作者Su Mi
相关产品推荐
相关产品推荐

