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

Flutter中Timer与Riverpod实现计数器时,终端与UI显示值不一致问题

Flutter Riverpod 按住按钮递增计数器:print值与UI显示不一致的解决方法

问题根源

你的问题核心在于本地成员变量与Riverpod状态源不同步,加上Timer配置不合理,导致终端输出和UI显示数值出现偏差:

  • build方法中用ref.watch(myStateProviderInt)覆盖本地counter_int,但Timer里先自增本地变量再更新provider状态,这会让print的是本地自增后的值,而provider状态是旧值加1,两者天然存在差异;同时每次UI刷新(build)时,本地变量又会被重置为provider当前状态,进一步打乱同步逻辑。
  • Timer间隔设为1ms,远快于Flutter UI刷新帧率(约16ms/帧),过高的状态更新频率会导致UI无法及时同步,还可能引发状态更新队列积压。

修正后的代码

class StateProviderPond extends ConsumerStatefulWidget {
  static const String page_id = 'goto_state';

  const StateProviderPond({Key? key}) : super(key: key);

  @override
  ConsumerState<StateProviderPond> createState() => _StateProviderPondState();
}

class _StateProviderPondState extends ConsumerState<StateProviderPond> {
  Timer? timerCounter;

  @override
  void dispose() {
    timerCounter?.cancel(); // 页面销毁时清理Timer,避免内存泄漏
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 直接从Riverpod获取唯一可信的状态源
    final counter = ref.watch(myStateProviderInt);

    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        backgroundColor: Colors.transparent,
        title: const Text('riverpod-state provider'),
        centerTitle: true,
        actions: [
          IconButton(onPressed: () {}, icon: const Icon(Icons.arrow_back_ios))
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            Text(
              '$counter',
              style: const TextStyle(fontSize: 50, color: Colors.white38),
            ),
            GestureDetector(
              child: const Center(
                child: Text('~', style: TextStyle(fontSize: 30, color: Colors.indigo)),
              ),
              onTapDown: (TapDownDetails details) {
                print('down');
                // 先取消旧Timer,防止多次触发导致多Timer并行
                timerCounter?.cancel();
                // 调整间隔为50ms,平衡递增流畅度与UI刷新压力
                timerCounter = Timer.periodic(const Duration(milliseconds: 50), (t) {
                  // 基于provider状态计算新值,同步更新并打印
                  final newCounter = ref.read(myStateProviderInt.notifier).state + 1;
                  ref.read(myStateProviderInt.notifier).state = newCounter;
                  print(newCounter);
                });
              },
              onTapUp: (TapUpDetails details) {
                timerCounter?.cancel();
                print('up');
                print('***********');
              },
            ),
          ],
        ),
      ),
    );
  }
}

关键修改说明

  • 将ConsumerWidget改为ConsumerStatefulWidget,在dispose中清理Timer,避免内存泄漏。
  • 移除本地counter_int变量,直接通过ref.watch获取Riverpod状态,确保UI显示的是唯一可信的数据源。
  • Timer内基于provider当前状态计算新值,同步更新状态并打印,保证终端输出与UI显示数值完全一致。
  • 调整Timer间隔为50ms,避免状态更新频率超过UI处理能力。
  • onTapDown中先取消旧Timer,防止多次按下导致多Timer并行引发数值跳变。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:45:42