Android Studio如何通过TextView实时持续显示动态更新的变量值

问题根因
你的代码存在两个直接导致积分无法实时显示的问题:
Timer的定时任务运行在独立子线程,Android系统限制只有主线程(UI线程)可以操作View控件,子线程直接调用setText更新TextView会触发线程异常,更新逻辑根本不会生效- 你仅在
onCreate页面初始化阶段给visibletotals赋值过一次,后续自动累加积分、点击加积分、升级扣积分的逻辑里,都没有同步更新这个总积分显示控件
修复方案
- 新增主线程
Handler,把定时任务里的UI更新逻辑切回主线程执行 - 抽离统一的积分刷新方法,所有修改
clicks积分值的位置都调用这个方法,避免漏更新 - 补充页面销毁时的
Timer取消逻辑,防止内存泄漏
直接替换为下面修正后的完整代码即可:
package com.example.idleclicker; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends AppCompatActivity { TextView points; TextView visibletotals; Button click; Button upgradebtn; TextView Leveltext; int clicks = 0; int clickcost = 10; int upgradelevel = 1; Timer myTimer = new Timer(); // 主线程Handler,用于将子线程任务切到UI线程执行 private final Handler mainHandler = new Handler(Looper.getMainLooper()); /** * 统一刷新积分显示,所有修改clicks值的逻辑后都调用该方法 */ private void updatePointsShow() { points.setText(getResources().getString(R.string.evol) + clicks); visibletotals.setText("Evolutions Points: " + clicks); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); click = findViewById(R.id.click); points = findViewById(R.id.points); upgradebtn = findViewById(R.id.upgradebtn); Leveltext = findViewById(R.id.leveltext); visibletotals = findViewById(R.id.visibletotals); // 初始化页面显示 updatePointsShow(); upgradebtn.setText(getResources().getString(R.string.Upgrade) + clickcost + getString(R.string.LevelText) + upgradelevel); myTimer.schedule(new TimerTask() { @Override public void run() { clicks += upgradelevel; // 切到主线程刷新UI mainHandler.post(() -> updatePointsShow()); } }, 0, 1000); click.setOnClickListener(view -> { clicks++; updatePointsShow(); }); upgradebtn.setOnClickListener(view -> { if (clicks >= clickcost) { clicks -= clickcost; upgradelevel += 1; clickcost *= 2; upgradebtn.setText(getResources().getString(R.string.Upgrade) + clickcost + getString(R.string.LevelText) + upgradelevel); // 扣除升级积分后同步刷新显示 updatePointsShow(); } }); } @Override protected void onDestroy() { super.onDestroy(); // 页面销毁时取消定时任务,避免内存泄漏 myTimer.cancel(); } }
注意事项
- Android的UI操作必须在主线程执行,子线程直接修改View属性会抛出
CalledFromWrongThreadException,这是平台基础规则 - 统一抽离刷新方法可以减少重复代码,后续新增其他修改积分的逻辑(比如道具加成、离线收益结算)时,只要在修改
clicks后调用updatePointsShow()即可,不需要重复写setText逻辑 - 定时任务、异步任务必须在页面销毁时主动取消,否则会持有Activity引用导致内存泄漏,后台空跑也会额外消耗设备性能
内容的提问来源于stack exchange,提问作者Allie Johnson
相关产品推荐
相关产品推荐

