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

Flutter集成Google Map返回页面时触发‘Looking up a deactivated widget's ancestor is unsafe’错误求助

我来帮你分析并解决这个Flutter集成Google Map时遇到的问题:

错误原因解析

你遇到的 "Looking up a deactivated widget's ancestor is unsafe" 错误,根源在于在Widget已失效的时机使用context获取依赖:

  • 在MapScreen的dispose方法中,你调用了Provider.of<ApplicationBloc>(context, listen: false),此时MapScreen已经从Widget树中被移除(处于deactivated状态),Flutter禁止在这个阶段通过context查找祖先元素,因为此时Widget树的状态已经不稳定。
  • 另外,你在页面的dispose里手动调用applicationBloc.dispose()也不合理——如果ApplicationBloc是通过Provider在全局/父级提供的,它的生命周期应该由Provider管理,手动提前销毁会导致其他依赖该Bloc的页面出现异常。

这个问题和你使用的Provider状态管理方式本身无关,只是错误时机使用context导致的。

解决方案

1. 提前保存Bloc实例,避免在dispose中使用context

在_MapScreenState中添加成员变量保存Bloc实例,在initState(此时context处于活跃状态)中获取并赋值,这样在dispose时直接使用这个变量即可:

class _MapScreenState extends State<MapScreen> {
  Completer<GoogleMapController> _mapController = Completer();
  late StreamSubscription locationSubscription;
  late StreamSubscription boundsSubscription;
  final _locationController = TextEditingController();
  // 新增:保存Bloc实例
  late ApplicationBloc _applicationBloc;

  @override
  void initState() {
    // 在initState中获取Bloc并保存,此时context是安全的
    _applicationBloc = Provider.of<ApplicationBloc>(context, listen: false);
    
    // 监听选中位置流
    locationSubscription = _applicationBloc.selectedLocation.stream.listen((place) {
      if (place != null) {
        _locationController.text = place.name ?? "";
        _goToPlace(place);
      } else {
        _locationController.text = "";
      }
    });

    // 监听地图 bounds 流(修正:将订阅对象赋值给boundsSubscription)
    boundsSubscription = _applicationBloc.bounds.stream.listen((bounds) async {
      final GoogleMapController controller = await _mapController.future;
      controller.animateCamera(CameraUpdate.newLatLngBounds(bounds, 50));
    });
    super.initState();
  }

  @override
  void dispose() {
    // 移除手动销毁Bloc的代码!Bloc的生命周期交给Provider管理
    // _applicationBloc.dispose();
    
    _locationController.dispose();
    locationSubscription.cancel();
    boundsSubscription.cancel();
    super.dispose();
  }

  // 其他代码保持不变
}

2. 让Provider自动管理Bloc的生命周期

确保你在父级组件(比如main.dart)中使用ChangeNotifierProvider提供Bloc,这样Provider会在合适的时机自动调用Bloc的dispose方法,不需要手动处理:

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => ApplicationBloc(),
      child: const MyApp(),
    ),
  );
}

这样当整个应用退出时,Provider会自动销毁ApplicationBloc,既避免内存泄漏,也不会出现提前销毁导致的异常。

额外修复点

你的代码中boundsSubscription在initState里没有正确赋值(之前的代码只是监听了流,但没有把订阅对象赋值给变量),这会导致dispose时调用boundsSubscription.cancel()报错,上面的代码已经帮你修正了这个问题。

内容的提问来源于stack exchange,提问作者Dilanka yapa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 22:27:34