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

Flutter Isolate定位报Binding has not yet been initialized错误

问题背景

开发谷歌地图定位应用时,创建Isolate实现获取位置功能时程序抛出错误,自行排查未修复。

项目使用依赖

  • google_maps_flutter: ^2.1.8
  • geocoding: ^2.0.4
  • geolocator: ^8.2.1
  • flutter_bloc: ^8.0.1

报错信息

Restarted application in 2,738ms.
D/MapsInitializer( 6872): preferredRenderer: null
D/zzca    ( 6872): preferredRenderer: null
I/Google Maps Android API( 6872): Google Play services package version: 221215028
I/Google Maps Android API( 6872): Google Play services maps renderer version(legacy): 2031150007
I/Counters( 6872): exceeded sample count in FrameTime
I/m.example.g_ma( 6872): NativeAlloc concurrent copying GC freed 17476(988KB) AllocSpace objects, 0(0B) LOS objects, 50% free, 7MB/14MB, paused 172us total 133.433ms10
I/Counters( 6872): exceeded sample count in FrameTime
I/m.example.g_ma( 6872): NativeAlloc concurrent copying GC freed 4201(193KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 7MB/14MB, paused 138us total 149.308ms7
I/Counters( 6872): exceeded sample count in FrameTime
I/chatty  ( 6872): uid=10498(com.example.g_map) androidmapsapi- identical 1 line3
I/Counters( 6872): exceeded sample count in FrameTime
E/flutter ( 6872): [ERROR:flutter/runtime/dart_isolate.cc(1098)] Unhandled exception:
E/flutter ( 6872): Binding has not yet been initialized.
E/flutter ( 6872): The "instance" getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
E/flutter ( 6872): Typically, this is done by calling "WidgetsFlutterBinding.ensureInitialized()" or "runApp()" (the latter calls the former). Typically this call is done in the "void main()" method. The "ensureInitialized" method is idempotent; calling it multiple times is not harmful. After calling that method, the "instance" getter will return the binding.
E/flutter ( 6872): In a test, one can call "TestWidgetsFlutterBinding.ensureInitialized()" as the first line in the test's "main()" method to initialize the binding.
E/flutter ( 6872): If ServicesBinding is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, but that mixes in the selected binding, and that is the class that must be constructed before using the "instance" getter.
E/flutter ( 6872): #0      BindingBase.checkInstance.<anonymous closure>
package:flutter/…/foundation/binding.dart:281
E/flutter ( 6872): #1      BindingBase.checkInstance
package:flutter/…/foundation/binding.dart:363
E/flutter ( 6872): #2      ServicesBinding.instance
package:flutter/…/services/binding.dart:48
E/flutter ( 6872): #3      MethodChannel.binaryMessenger
package:flutter/…/services/platform_channel.dart:132

相关代码

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:g_map/cubit/googlemap_cubit.dart';
import 'screens/home_page.dart';

void main() async{
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider<GooglemapCubit>(
      create: (context) => GooglemapCubit(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(title: 'Flutter Map'),
      ),
    );
  }
}

位置权限工具类

import 'dart:developer';
import 'package:geolocator/geolocator.dart';

class GLocationPermission{
  Future<bool> checkPermission()async{
    bool serviceEnabled ;
    LocationPermission permission;
  
    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if(!serviceEnabled){
      log("",error: "Location service is not enabled");
    }

    permission = await Geolocator.checkPermission();
    if(permission == LocationPermission.denied){
      permission = await Geolocator.requestPermission();
      if(permission == LocationPermission.denied){
        log("Permission is denied again ");
      }
    }

    if(permission == LocationPermission.deniedForever){
      log("",error: "Location permission denied forever");
      return false;
    }

    if(permission == LocationPermission.whileInUse || permission == LocationPermission.always){
      return true;
    }else{
      return false;
    }
  }
}

首页实现

import 'dart:developer';
import 'dart:isolate';

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:g_map/isolates/current_location_in_background.dart';
import 'package:g_map/services/location_permission.dart';
import 'package:geocoding/geocoding.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>{
  late GoogleMapController _mapController;
  final TextEditingController _searchAddressController = TextEditingController();
  final _locationPermission = GLocationPermission();
  String searchedAddress = "";

  late ReceivePort _receivePort;
  late Isolate _isolate;

  @override
  void initState() {
    _checkPermission();
    super.initState();
  }

  Future<void> _checkPermission()async{
    if(await _locationPermission.checkPermission() == true){
      createIsloate();
    }
  }

  Future<void> createIsloate()async{
    _receivePort = ReceivePort();
    _isolate = await Isolate.spawn(CurrentLocationInBackGround.getLocation,  _receivePort.sendPort);
    _receivePort.listen((message) {
      log("message $message");
    },
    onError: (error){
      log("Error $error",error: error);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Stack(
          children: [
            _googleMap(
                inititalCameraPosition: const CameraPosition(
              target: LatLng(37.42796133580664, -122.085749655962),
            )),
            _searchAddressField(context: context)
          ],
        ));
  }

  Widget _googleMap({required CameraPosition inititalCameraPosition}) {
      return GoogleMap(
        zoomControlsEnabled: true,
        onMapCreated: _onMapCreated,
        myLocationButtonEnabled: true,
        initialCameraPosition: inititalCameraPosition,
      );
  }

  Widget _searchAddressField({required BuildContext context}){
    return Card(
      child: SizedBox(
        width: double.infinity,
        height: MediaQuery.of(context).size.height*.07,
        child: Center(
          child: TextField(
            onChanged: (value){},
            controller: _searchAddressController,
            decoration: InputDecoration(border: InputBorder.none,
            suffix: IconButton(onPressed:() => _searchAndNavigate(context: context), icon: const Icon(Icons.search))
            ),
          ),
        ),
      ),
    );
  }

  Future<void> _searchAndNavigate({required BuildContext context})async{
        final location = GeocodingPlatform.instance.locationFromAddress(_searchAddressController.text);
        location.then((value){
        debugPrint(value[0].latitude.toString());
        debugPrint(value[0].longitude.toString());
        _mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
          zoom: 12,
          target:LatLng(value[0].latitude, value[0].longitude))));
      });   
  }

  void _onMapCreated(GoogleMapController controller) {
    _mapController = controller;
  }
}

后台定位Isolate代码

import 'dart:developer';
import 'dart:isolate';

import 'package:geolocator/geolocator.dart';

class CurrentLocationInBackGround{
  static void getLocation(SendPort sendPort)async{
    final pos = await Geolocator.getCurrentPosition();
    log("pos stream $pos");
    sendPort.send(pos);
  }
}

问题原因

通过Isolate.spawn创建的是独立工作线程,不会自动继承主Isolate的Flutter引擎绑定初始化状态。geolocator这类基于MethodChannel实现的插件,底层通信依赖ServicesBinding提供的二进制信使,新创建的普通Isolate没有初始化该绑定,直接调用插件就会抛出Binding has not yet been initialized错误。

修复方案

  • 单次获取位置不需要额外创建Isolate:Geolocator.getCurrentPosition()本身是异步非阻塞调用,不会阻塞UI线程,直接在主Isolate中调用即可,删除自定义Isolate创建、监听相关的冗余代码就能解决问题,这是最简单稳妥的方案。
  • 如果需要实现后台持续定位,不要自行创建普通Isolate:直接使用geolocator自带的后台位置能力,或使用专门的后台服务插件处理跨Isolate的引擎初始化逻辑。
  • 若必须在自定义Isolate中调用插件,需要先把主Isolate的token传给新Isolate,再初始化后台信使:
    1. 主Isolate创建Isolate时传入token:
    _isolate = await Isolate.spawn(
      CurrentLocationInBackGround.getLocation,
      [_receivePort.sendPort, RootIsolateToken.instance!]
    );
    
    1. Isolate入口处初始化绑定:
    static void getLocation(List<dynamic> args)async{
      SendPort sendPort = args[0];
      RootIsolateToken token = args[1];
      BackgroundIsolateBinaryMessenger.ensureInitialized(token);
      DartPluginRegistrant.ensureInitialized();
      final pos = await Geolocator.getCurrentPosition();
      log("pos stream $pos");
      sendPort.send(pos);
    }
    
    注意普通Isolate无法执行UI相关操作,所有UI更新逻辑必须把数据通过SendPort传回主Isolate处理。

内容的提问来源于stack exchange,提问作者Vikash Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:48:23