简体   繁体   English

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

[英]Flutter GoogleMap is blank after resuming from background

I'm experiencing the following issue: My Flutter app uses a GoogleMap.我遇到以下问题:我的 Flutter 应用使用 GoogleMap。 The map loads just fine initially.地图最初加载得很好。 However, if I put the app into the background and resume a while later, the map stays blank.但是,如果我将应用程序置于后台并稍后恢复,则地图将保持空白。 The Google logo still shows, like it happens when the API key isn't specified. Google 徽标仍然显示,就像未指定 API 密钥时一样。 My polygon overlay doesn't show up, either.我的多边形叠加层也没有出现。

The behavior is not reliably repruducable.该行为不能可靠地重现。 Sometimes, the map loads fine after the app had been in the background for hours, sometimes the map is blank after minutes.有时,应用程序在后台运行数小时后地图加载正常,有时地图在几分钟后为空白。 So far, I have only seen this behavior on Android.到目前为止,我只在 Android 上看到过这种行为。

There are no specific log outputs that indicate an error.没有指示错误的特定日志输出。

Any ideas how to fix/work around this?任何想法如何解决/解决这个问题?

I filed an issue with screenshot here: https://github.com/flutter/flutter/issues/40284我在这里提出了一个截图问题: https ://github.com/flutter/flutter/issues/40284

EDIT 1: I was able to reproduce this with a GoogleMap as root widget and also without any polygon/feature overlay.编辑 1:我能够使用 GoogleMap 作为根小部件来重现它,并且没有任何多边形/特征覆盖。 Also, I found that wildly zooming in at some point 'reanimates' the map (suddenly the map becomes visible again).此外,我发现在某些时候疯狂放大地图会“重新激活”地图(突然地图再次变得可见)。 Is this maybe a known issue with the underlying Android Google Maps SDK?这可能是底层 Android Google Maps SDK 的已知问题吗?

EDIT 2: I found that the map is still reacting (eg tap/gesture listeners still trigger).编辑2:我发现地图仍在反应(例如,点击/手势监听器仍然触发)。 Also, the map isn't really empty, it just becomes translucent, so the screen displays whatever widget is behind the map.此外,地图并不是真正的空,它只是变得半透明,因此屏幕会显示地图后面的任何小部件。

I discovered that if you tap a marker or change the style the map re-renders我发现如果您点击标记或更改地图重新渲染的样式

class TheWidgetThatHasTheMap with WidgetsBindingObserver {

   //...your code

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

Not a solution to the core problem, but I was able to work around this bug by creating a fork of the plugins project and modifying GoogleMapController.java as follows:不是核心问题的解决方案,但我能够通过创建插件项目的分支并修改 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());
    }
  }

Now, on every resume event, the map will be re-rendered.现在,在每个恢复事件中,都会重新渲染地图。

I tried something & it seems to be working!我尝试了一些东西,它似乎正在工作!

Step 01, Implement WidgetsBindingObserver for related class's State class as follows, ie:步骤01,为相关类的State类实现WidgetsBindingObserver如下,即:

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

Step 02, Override didChangeAppLifecycleState method ie:步骤 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;
    }
  }

Step 03 add this for init state Step 03 为初始化状态添加这个

WidgetsBinding.instance!.addObserver(this);

Step 04 Step 4 should be as follows Step 04 Step 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;
    }
  }

When dealing with a stateful widget, put the code below in your code as shown below在处理有状态的小部件时,将下面的代码放入您的代码中,如下所示

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("[]");
       }
    }
 }

Then you can add the code below in the state widget然后您可以在状态小部件中添加以下代码

Another simpler way to implement solution with setMapStyle within statefull widget of map widget.在地图小部件的全状态小部件中使用 setMapStyle 实现解决方案的另一种更简单的方法。 No need to change anything else: Import flutter services:无需更改任何其他内容:导入 Flutter 服务:

import 'package:flutter/services.dart';

Code:代码:

  SystemChannels.lifecycle.setMessageHandler((msg) {
      if (msg == AppLifecycleState.resumed.toString()) {
        mapController.setMapStyle("[]");
      }
    });

"mapController" here is the instance of Google map controller you named somewhere in your code.这里的“mapController”是您在代码中某处命名的 Google 地图控制器的实例。 In my case it is like this:就我而言,它是这样的:

  GoogleMapController _mapController;
  GoogleMapController get mapController => _mapController;
 if you facing this problem in 2022 also add this line above your class

class YourClass extends StatefulWidget with WidgetsBindingObserver类 YourClass 使用 WidgetsBindingObserver 扩展 StatefulWidget

Completer<GoogleMapController> controller = Completer();
    
          @override
            void dispose() {
    
              WidgetsBinding.instance!.removeObserver(this);
            
              super.dispose();
            }
              @override
              void didChangeAppLifecycleState(AppLifecycleState state) async {
                  super.didChangeAppLifecycleState(state);
                print('\n\ndidChangeAppLifecycleState');
             
                    if (state == AppLifecycleState.resumed) {
                        final GoogleMapController controller1 = await controller.future;
                        controller1.setMapStyle('[]');
                }
                
              }
        
        
          void initState() {                             
        
            super.initState();
              
            WidgetsBinding.instance!.addObserver(this);
          }

Another temporary fix that doesn't required forking the plugins, building, etc.另一个不需要分叉插件、构建等的临时修复。
Add a didChangeAppLifecycleState implemented via WidgetsBindingObserver to your Widget and make the GoogleMap widget rebuild with a state change.将通过WidgetsBindingObserver实现的didChangeAppLifecycleState添加到您的 Widget 并使用状态更改重建 GoogleMap 小部件。

In my case the map threw a black screen when called setState, the below solution solved my problem.在我的情况下,地图在调用 setState 时会出现黑屏,下面的解决方案解决了我的问题。

return SingleChildScrollView(
  physics: const NeverScrollableScrollPhysics(),
  child:SizedBox(
    width: MediaQuery.of(context).size.width,
    height: MediaQuery.of(context).size.height,
    child: //Your GoogleMap here,
  ),
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM