You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:启动Activity后计时器触发线程操作视图错误

问题原因分析

你遇到的Only the original thread that created a view hierarchy can touch its views错误,核心原因是:TimerTask的run()方法是在后台线程执行的——哪怕你在UI线程调用startTimer(),TimerTask的任务逻辑依然会在非UI线程运行,而Android规定只有创建View的原始线程(即UI线程)才能更新View,所以直接在TimerTask里调用timerText.setText()会触发这个错误。你之前用runOnUiThread包裹startTimer()完全没用,因为问题出在TimerTask内部的UI更新操作。

解决方案

下面给出几种可靠的修复方式,按推荐程度排序:

方案一:直接在TimerTask中包裹UI更新操作

修改startTimer()方法,仅把更新TextView的代码放到runOnUiThread里:

private void startTimer() {
    timerTask = new TimerTask() {
        @Override
        public void run() {
            time++;
            // 仅将UI更新逻辑切换到UI线程
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    timerText.setText(getTimerText());
                }
            });
        }
    };
    timer.scheduleAtFixedRate(timerTask, 0, 1000);
}

方案二:用Handler替代Timer(更推荐,适配Android线程模型)

Handler天生和UI线程绑定,用它实现定时循环更安全,还能避免Timer可能出现的线程泄漏问题:

private Handler handler = new Handler(Looper.getMainLooper());
private Runnable timerRunnable;
Double time = 0.0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ... 原有初始化代码不变
    timerText = (TextView) findViewById(R.id.timerText);
    startTimer();
}

private void startTimer() {
    timerRunnable = new Runnable() {
        @Override
        public void run() {
            time++;
            timerText.setText(getTimerText());
            // 每隔1秒重复执行当前任务
            handler.postDelayed(this, 1000);
        }
    };
    // 立即启动任务
    handler.post(timerRunnable);
}

// 必须在Activity销毁时移除回调,防止内存泄漏
@Override
protected void onDestroy() {
    super.onDestroy();
    if (handler != null && timerRunnable != null) {
        handler.removeCallbacks(timerRunnable);
    }
}

方案三:使用AndroidX的CountDownTimer(变种实现递增计时)

CountDownTimer是Android官方提供的定时工具,虽然设计用于倒计时,但可以改造成递增计时:

private CountDownTimer countDownTimer;
private long totalSeconds = 0;

private void startTimer() {
    // 设置总时长为24小时(足够日常使用),每隔1秒触发一次回调
    countDownTimer = new CountDownTimer(86400000, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
            totalSeconds++;
            int seconds = (int) (totalSeconds % 60);
            int minutes = (int) ((totalSeconds / 60) % 60);
            timerText.setText(formatTime(seconds, minutes));
        }

        @Override
        public void onFinish() {
            // 时长耗尽后重新启动,实现无限递增
            startTimer();
        }
    }.start();
}

// 销毁时取消定时器
@Override
protected void onDestroy() {
    super.onDestroy();
    if (countDownTimer != null) {
        countDownTimer.cancel();
    }
}
注意事项
  • 所有涉及View更新的代码必须放在UI线程执行
  • 无论用哪种方案,都要在Activity销毁时停止定时任务,避免内存泄漏

内容的提问来源于stack exchange,提问作者Acecryz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 15:35:25