我遇到了以下问题:我的Flutter应用程序使用GoogleMap。地图最初加载正常。但是,如果我将应用程序置于后台并在一段时间后恢复,则地图将保持空白。Google 徽标仍然显示,就像未指定 API 密钥时发生的那样。我的多边形叠加层也没有显示。
该行为不能可靠地重现。有时,在应用程序在后台运行数小时后,地图加载正常,有时地图在几分钟后为空白。到目前为止,我只在Android上看到过这种行为。
没有指示错误的特定日志输出。
任何想法如何修复/解决此问题?
我在这里提交了屏幕截图问题:https://github.com/flutter/flutter/issues/40284
编辑1:我能够使用GoogleMap作为根小部件来重现它,并且没有任何多边形/要素叠加。此外,我发现在某个时候疯狂放大会"激活"地图(突然地图再次变得可见(。这可能是底层Android Google Maps SDK的已知问题吗?
编辑2:我发现地图仍在反应(例如,点击/手势侦听器仍然触发(。此外,地图并不是真正的空的,它只是变得半透明,因此屏幕会显示地图后面的任何小部件。
我发现,如果您点击标记或更改样式,地图会重新渲染
class TheWidgetThatHasTheMap with WidgetsBindingObserver {
//...your code
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
controller.setMapStyle("[]");
}
}
}
不是核心问题的解决方案,但我能够通过创建插件项目的分支并修改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());
}
}
现在,在每个恢复事件中,将重新渲染地图。
我尝试了一些东西,它似乎正在工作!
步骤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;
}
}
处理有状态小部件时,将下面的代码放在代码中,如下所示
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("[]");
}
}
}
然后你可以在状态小部件中添加下面的代码
另一种更简单的方法,可以在地图小部件的有状态小部件中使用setMapStyle实现解决方案。无需更改任何其他内容: 导入颤振服务:
import 'package:flutter/services.dart';
法典:
SystemChannels.lifecycle.setMessageHandler((msg) {
if (msg == AppLifecycleState.resumed.toString()) {
mapController.setMapStyle("[]");
}
});
这里的"mapController"是你在代码中某处命名的谷歌地图控制器的实例。就我而言,它是这样的:
GoogleMapController _mapController;
GoogleMapController get mapController => _mapController;
if you facing this problem in 2022 also add this line above your class
类 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('nndidChangeAppLifecycleState');
if (state == AppLifecycleState.resumed) {
final GoogleMapController controller1 = await controller.future;
controller1.setMapStyle('[]');
}
}
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
}
另一个不需要分叉插件、构建等的临时修复
添加一个通过WidgetsBindingObserver
实现的didChangeAppLifecycleState
到你的小部件中,并通过状态更改重建谷歌地图小部件。
就我而言,地图在调用setState时会抛出黑屏,以下解决方案解决了我的问题。
return SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child:SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: //Your GoogleMap here,
),
);