从后台恢复后,Flutter GoogleMap 为空白

Posted

技术标签:

【中文标题】从后台恢复后,Flutter GoogleMap 为空白【英文标题】:Flutter GoogleMap is blank after resuming from background 【发布时间】:2020-04-09 22:37:39 【问题描述】:

我遇到了以下问题:我的 Flutter 应用使用了 GoogleMap。地图最初加载得很好。但是,如果我将应用程序置于后台并稍后恢复,则地图将保持空白。 Google 徽标仍然显示,就像未指定 API 密钥时一样。我的多边形叠加层也没有显示出来。

该行为不能可靠地重现。有时,应用程序在后台运行数小时后地图加载正常,有时地图在几分钟后为空白。到目前为止,我只在 android 上看到过这种行为。

没有指示错误的特定日志输出。

任何想法如何解决/解决这个问题?

我在这里提交了一个截图问题:https://github.com/flutter/flutter/issues/40284

编辑 1: 我能够使用 GoogleMap 作为根小部件来重现这一点,并且也没有任何多边形/特征覆盖。此外,我发现在某些时候疯狂放大地图会“重新激活”地图(突然地图再次变得可见)。这可能是底层 Android Google Maps SDK 的已知问题吗?

编辑 2: 我发现地图仍在反应(例如,点击/手势侦听器仍会触发)。此外,地图并不是真正的空,它只是变得半透明,因此屏幕会显示地图后面的任何小部件。

【问题讨论】:

这可能是个愚蠢的问题,但你能缩小地图吗?从截图看来是放大到了“地面”级别。 没有愚蠢的问题。 :-) 是的,它尝试了缩放,但它不起作用。此外,底图是卫星地图,因此至少会显示一些颜色。 【参考方案1】:

不是核心问题的解决方案,但我能够通过创建插件项目的分支并如下修改 GoogleMapController.java 来解决此错误:

@Override
  public void onActivityResumed(Activity activity) 
    if (disposed || activity.hashCode() != registrarActivityHashCode) 
      return;
    
    mapView.onResume();
    // Workaround for https://github.com/flutter/flutter/issues/40284
    // This apparently forces a re-render of the map.
    if (googleMap != null) 
      googleMap.setMapType(googleMap.getMapType());
    
  

现在,在每个恢复事件中,地图都会重新渲染。

【讨论】:

此解决方案工作了一段时间,然后将应用程序设置为 for 和 background 几次后,问题再次出现【参考方案2】:

我发现如果您点击标记或更改地图重新渲染的样式

class TheWidgetThatHasTheMap with WidgetsBindingObserver 

   //...your code

    @override
    void didChangeAppLifecycleState(AppLifecycleState state) 
        if (state == AppLifecycleState.resumed) 
            controller.setMapStyle("[]");
        
    

【讨论】:

我尝试在onMapCreated 中使用GoogleMapController 控制器,但它没有setMapStyle 方法 @kashlo 如果你的控制器被定义为 Completer _controller = Completer();那么你需要先用最终的 GoogleMapController controller = await _controller.future; 来检索它。 setMapStyle 将会出现。 知道当地图在选项卡中时该怎么做吗? didChangeAppLifecycleState 没有在我的选项卡中调用,仅在我的 HomeWidget(包含选项卡)中调用 @Thomas 我在选项卡中也遇到了同样的问题,我通过使用下面的代码解决了它尝试使用它并让我知道它是否适合你。代码:SystemChannels.lifecycle.setMessageHandler((msg) debugPrint('SystemChannels> $msg'); if(msg==AppLifecycleState.resumed.toString())setState(() _mapsController.setMapStyle("[]"); ); ); @VajaniKishan 我会试试的。你把它放在 Tab 本身的 initState() 中了吗?【参考方案3】:

另一个不需要分叉插件、构建等的临时修复。 将通过WidgetsBindingObserver 实现的didChangeAppLifecycleState 添加到您的小部件,并使GoogleMap 小部件通过状态更改重建。

【讨论】:

【参考方案4】:

我尝试了一些东西,它似乎正在工作!

步骤 01, 为相关类的State类实现WidgetsBindingObserver如下, 即:

class MainScreenState extends State<MainScreen> with WidgetsBindingObserver ....

步骤02, 覆盖 didChangeAppLifecycleState 方法 即:

@override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async 
    super.didChangeAppLifecycleState(state);
    switch (state) 
      case AppLifecycleState.inactive:
        print('appLifeCycleState inactive');
        break;
      case AppLifecycleState.resumed:
        print('appLifeCycleState resumed');
        break;
      case AppLifecycleState.paused:
        print('appLifeCycleState paused');
        break;
      case AppLifecycleState.detached:
        print('appLifeCycleState detached');
        break;
    
  

步骤 03 为初始化状态添加这个

WidgetsBinding.instance!.addObserver(this);

步骤 04 第4步应该如下

//onMapCreated method
  void onMapCreated(GoogleMapController controller) 
    controller.setMapStyle(Utils.mapStyles);
    _controller.complete(controller);
  
// lifecycle
  @override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async 
    super.didChangeAppLifecycleState(state);
    switch (state) 
      case AppLifecycleState.inactive:
        print('appLifeCycleState inactive');
        break;
      case AppLifecycleState.resumed:
        **//Add These lines**
        final GoogleMapController controller = await _controller.future;
        onMapCreated(controller);
        print('appLifeCycleState resumed');
        break;
      case AppLifecycleState.paused:
        print('appLifeCycleState paused');
        break;
      case AppLifecycleState.detached:
        print('appLifeCycleState detached');
        break;
    
  

【讨论】:

谢谢....你有使用Flutter Hooks的例子吗? 没有,但是这个链接有。 medium.com/flutter-community/…【参考方案5】:

在处理有状态的小部件时,将下面的代码放在你的代码中,如下所示

class MainScreenState extends State<MainScreen> with WidgetsBindingObserver 
 ....


  @override
  void initState() 
     super.initState();
     WidgetsBinding.instance!.addObserver(this);
     ...    // Other codes here 
  


  @override
  void didChangeAppLifecycleState(AppLifecycleState state) 
       if (state == AppLifecycleState.resumed) 
         mapController!.setMapStyle("[]");
       
    
 

然后你可以在状态小部件中添加下面的代码

【讨论】:

以上是关于从后台恢复后,Flutter GoogleMap 为空白的主要内容,如果未能解决你的问题,请参考以下文章

Flutter GoogleMap Provider Context问题

Flutter中如何在PageView中正确使用GoogleMap

GoogleMap,如何在单击 Market en Flutter 时删除图标

游戏从后台快速恢复后退出暂停状态

Chirp Audio QR 从后台恢复后 ipad 无法接收音频信号

从后台恢复显示 ModalViewController,避免下面的内容闪烁