5

I'm attempting to run location updates on a Flutter isolate thread, the error is only present when running an isolate. Location requests works without issues on the main thread. The goal here is to run this as a background service, working with dart code only. I am using Geolocator plugin for location requests.

This is the error I am facing when starting the isolate:

Exception has occurred. FlutterError (ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized.

I have tried to include the WidgetsFlutterBinding.ensureInitialized() before runApp but without results. Looking at the call stack of the error, it seems problems occur at the android location platform call: checkPermissionStatus This happens regardless of what location plugin I am using, it stops at the permission status check.

I have figured it could have something to do with awaiting location permission user input, but this check will fail on a non-ui thread?

See this simple main.dart file for an example:

import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Isolate location test',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Isolate location test'),
    );
  }
}

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

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Isolate isolate;
  bool isRunning = false;
  String output = '';
  ReceivePort receivePort;

  void start() async {
    receivePort = ReceivePort();
    await Isolate.spawn(locationUpdate, receivePort.sendPort);
    receivePort.listen((dynamic data) {
      setState(() {
        isRunning = true;
      });
    }, onDone: () {
      print("done");
    });
  }

  void stop() {
    if (isolate != null) {
      setState(() {
        isRunning = false;
      });
      receivePort.close();
      isolate.kill(priority: Isolate.immediate);
      isolate = null;
    }
  }

  static void locationUpdate(SendPort sendPort) async {
    Geolocator().checkGeolocationPermissionStatus().then((status) {
      sendPort.send(status);
    });
    // Geolocator().getCurrentPosition().then((pos) {
    //   sendPort.send(pos);
    // });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(child: Text(output)),
      floatingActionButton: FloatingActionButton(
        onPressed: isRunning ? stop : start,
        child: Icon(isRunning ? Icons.stop : Icons.play_circle_filled),
      ),
    );
  }
}
nplus
  • 51
  • 4
  • I've used `WidgetsFlutterBinding.ensureInitialized();` before `runApp`. I don't know about `TestWidgetsFlutterBinding.ensureInitialized()`. I don't know if this is related to your issue. I know Flutter plugins and isolates were not a possible combination not long ago. I don't know how good that functionality is now. – Ted Henry Feb 08 '20 at 19:12
  • @Ted Henry: my mistake, I meant `WidgetsFlutterBinding`, copied wrong text from the error. Well that's good insight, I don't actually have big hopes to get this working with only Flutter code. – nplus Feb 08 '20 at 19:27
  • Are you thinking to write the geolocation code in native Kotlin and Swift code in separate threads and then send results to the Dart code using an `EventChannel`? – Ted Henry Feb 08 '20 at 19:37
  • 1
    If I need to go with native code, my case would probably look like: from Dart, start a separate native background service with the geolocation logic (which saves location data to local storage or similar), then with Dart code using a call to stop the service and retrieve the location results. I assume I only need a MethodChannel here – nplus Feb 08 '20 at 20:53
  • That's seems like a reasonable way to start if you need to go with native code. – Ted Henry Feb 08 '20 at 20:59

0 Answers0