Flutter withClock模拟时钟调用WidgetsFlutterBinding.ensureInitialized()时行为异常
Flutter withClock模拟时钟失效问题:原因与解决办法
问题本质
先调用WidgetsFlutterBinding.ensureInitialized()再用withClock包裹runApp时,会出现build方法内能拿到模拟时间,但build外的方法(比如按钮点击回调)只能拿到真实时间的情况。核心原因是:
WidgetsFlutterBinding.ensureInitialized()会提前启动Flutter核心绑定框架,包括初始化事件循环、后台线程等组件,这些组件的调用栈不在withClock的作用域内。runApp在withClock内执行,build方法由Flutter框架在withClock作用域调度,所以能正常获取模拟时间;但按钮点击这类交互事件由Flutter事件循环线程处理,该线程调用栈不受外层withClock影响,因此clock.now()会返回真实时间。
解决办法
把WidgetsFlutterBinding.ensureInitialized()移到withClock的回调内部,让Flutter绑定的整个初始化过程都处于模拟时钟的作用域中,这样所有后续框架任务(包括事件回调)都会继承这个模拟环境:
修改后的main函数代码:
void main() { withClock(Clock.fixed(DateTime(1990)), () { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); }); }
验证效果
修改后,无论是build方法里的clock.now(),还是_printClockNow按钮回调中的打印,都会返回预设的1990年模拟时间,所有地方时钟表现一致,测试可正常进行。
完整修改后代码
import 'package:clock/clock.dart'; import 'package:flutter/material.dart'; void main() { withClock(Clock.fixed(DateTime(1990)), () { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); }); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { void _printClockNow() { print('_printClockNow is: ${clock.now()}'); // 现在会打印模拟的1990年时间 setState(() {}); } @override Widget build(BuildContext context) { print('build clock.now() is: ${clock.now()}'); // 打印模拟时间 return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: const <Widget>[Dummy()], ), ), floatingActionButton: FloatingActionButton( onPressed: _printClockNow, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } } class Dummy extends StatelessWidget { const Dummy({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Text('t: ${clock.now()}'); } }
内容的提问来源于stack exchange,提问作者Maciej Pszczolinski
相关产品推荐
相关产品推荐

