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
相关产品推荐
相关产品推荐

