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

Flutter build方法先于变量初始化导致崩溃 如何提前初始化参数

Flutter 异步初始化会话变量解决build执行早于initState异步逻辑崩溃问题

问题根因

  • initState 是同步生命周期方法,内部调用的异步 setGps 方法不会阻塞后续 build 执行,你从 FlutterSession 取的经纬度可能为空,或未等赋值完成就被使用,传给 LatLng 空值就会触发崩溃。
  • 不存在让 build 等待 initState 异步执行完的方法,正确解法是用 FutureBuilder 控制渲染逻辑:异步加载完成前显示加载占位,加载完成再渲染地图页面。

修改步骤说明

  1. 调整setGps方法,直接返回处理后的LatLng对象,同时新增空值兜底逻辑,避免会话无值时传入空参数崩溃
  2. 用FutureBuilder包裹原有页面逻辑,根据异步执行状态返回对应组件:加载中显示加载提示,加载完成再渲染地图
  3. 移除冗余的状态更新逻辑,直接用Future返回的经纬度初始化地图参数

完整可运行代码

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:permission/permission.dart';
import 'package:flutter_session/flutter_session.dart';

class GmyApp extends StatefulWidget {
  const GmyApp({Key? key}) : super(key: key);
  @override
  _GmyApp createState() => _GmyApp();
}

class _GmyApp extends State<GmyApp> {
  Completer<GoogleMapController> _controller = Completer();
  static const LatLng _defaultCenter = const LatLng(10.8505, 76.2711);
  final Set<Marker> _markers = {};
  late LatLng _lastMapPosition;
  MapType _currentMapType = MapType.normal;
  // 声明异步加载的Future
  late Future<LatLng> _loadPositionFuture;

  void _onMapTypeButtonPressed() {
    setState(() {
      _currentMapType = _currentMapType == MapType.normal
          ? MapType.satellite
          : MapType.normal;
    });
  }

  void _onAddMarkerButtonPressed() {
    setState(() {
      _markers.add(Marker(
        markerId: MarkerId(_lastMapPosition.toString()),
        position: _lastMapPosition,
        infoWindow: InfoWindow(
          title: 'Your last location',
          snippet: 'Location Refreshed every 1 hour',
        ),
        icon: BitmapDescriptor.defaultMarker,
      ));
    });
  }

  void _onCameraMove(CameraPosition position) {
    _lastMapPosition = position.target;
  }

  void _onMapCreated(GoogleMapController controller) {
    _controller.complete(controller);
  }

  @override
  void initState() {
    super.initState();
    // 初始化时就启动异步加载,赋值给Future变量
    _loadPositionFuture = setGps();
  }

  // 修改setGps为返回LatLng的Future,新增空值兜底
  Future<LatLng> setGps() async {
    print('I am in GPS setter*');
    var latitude_data = await FlutterSession().get('lat');
    var longitude_data = await FlutterSession().get('longi');
    print('User logi Id is in GPS* $longitude_data');
    print('User lat is in GPS* $latitude_data');
    // 空值判断,会话取不到就用默认坐标
    if (latitude_data == null || longitude_data == null) {
      _lastMapPosition = _defaultCenter;
      return _defaultCenter;
    }
    LatLng center1 = LatLng(latitude_data, longitude_data);
    print('Lat .lat is in GPS  $center1');
    _lastMapPosition = center1;
    print('Lat .lat lastMap Position is  $_lastMapPosition');
    return center1;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Your Current Location is'),
          backgroundColor: Colors.green[700],
        ),
        // 用FutureBuilder包裹原有body逻辑
        body: FutureBuilder<LatLng>(
          future: _loadPositionFuture,
          builder: (context, snapshot) {
            // 加载中显示居中加载提示
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const Center(child: CircularProgressIndicator());
            }
            // 加载出错显示错误提示
            if (snapshot.hasError) {
              return Center(child: Text('加载位置信息失败:${snapshot.error}'));
            }
            // 加载完成,正常渲染地图
            return Stack(
              children: <Widget>[
                GoogleMap(
                  onMapCreated: _onMapCreated,
                  initialCameraPosition: CameraPosition(
                    target: _lastMapPosition,
                    zoom: 11.0,
                  ),
                  mapType: _currentMapType,
                  markers: _markers,
                  onCameraMove: _onCameraMove,
                ),
                Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Align(
                    alignment: Alignment.topRight,
                    child: Column(
                      children: <Widget> [
                        FloatingActionButton(
                          onPressed: _onMapTypeButtonPressed,
                          heroTag: "btn1",
                          materialTapTargetSize: MaterialTapTargetSize.padded,
                          backgroundColor: Colors.green,
                          child: const Icon(Icons.map, size: 36.0),
                        ),
                        SizedBox(height: 16.0),
                        FloatingActionButton(
                          onPressed: _onAddMarkerButtonPressed,
                          heroTag: "btn2",
                          materialTapTargetSize: MaterialTapTargetSize.padded,
                          backgroundColor: Colors.green,
                          child: const Icon(Icons.add_location, size: 36.0),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

额外注意点

  • 代码适配了Flutter 2.0+的空安全语法,如果你的项目是旧版本非空安全,把变量声明里的?和late关键字去掉即可
  • 已经新增了空值兜底逻辑,就算会话里没有存储经纬度,也会用默认坐标渲染,不会崩溃
  • 加载过程中会显示圆形加载指示器,用户感知更友好

内容的提问来源于stack exchange,提问作者Ashin ashin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:27:02