Widget的BuildContext生命周期时长?为何延迟路由跳转触发异常?
Flutter中BuildContext在路由操作中的存活时长疑问
我理解每个Widget的context都是唯一的,包含它在Widget树中的位置信息。当弹出导航路由时,对应的Widget会从导航栈中移除并最终销毁。
我做了两组测试:
- 点击Widget(按钮/手势检测器)弹出应用抽屉后立即推送新路由,一切正常;
- 但把推送命令放到延迟的Future里时,就会触发异常:
Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
代码示例1
Navigator.of(context).pop(); Future.delayed(const Duration(seconds: 2), () { Navigator.of(context).pushNamed('foo_route'); });
结果:触发上述异常
代码示例2
Navigator.of(context).pop(); Navigator.of(context).pushNamed('foo_route');
结果:正常运行,抽屉弹出后成功推送新路由
我清楚这个异常的触发原因,但疑惑为什么第二段代码不会出问题——看起来BuildContext的存活时长比我预想的要短很多?
原因解析
这是因为Flutter的路由操作是同步调度的:
- 代码示例2中,
pop()和pushNamed()是连续同步执行的。虽然pop()会标记当前Widget要被移除,但在当前的事件循环帧里,Widget还没被实际销毁,BuildContext仍然有效。Navigator的所有操作都在同一帧内完成,所以不会触发异常。 - 代码示例1里,
Future.delayed()会把pushNamed()放到延迟后的事件循环执行。这时候之前的Widget已经被从Widget树中移除并销毁了,对应的BuildContext也变成了失效状态,再用它去获取Navigator就会触发异常。
简单总结:同步操作时,Context还没来得及被销毁;延迟异步操作时,Context已经被销毁了。
内容的提问来源于stack exchange,提问作者Kaustubh Dixit
相关产品推荐
相关产品推荐

