3

I have a simple greeter gRPC example server code written in go and exported as C library that I'm trying to run with a flutter app using go-flutter desktop engine via ffi and dart Isolates.

I have made a StopGrpc() function, which works if I call it to stop gRPC server.

But if I don't manually first trigger the StopGrpc() function before exiting the application I keep getting the following waiting for isolates _startGrpc to check in which never ends, and I have to force quit the application.

An Observatory debugger and profiler on Flutter test device is available at: http://127.0.0.1:50300/
go-flutter: closing application
Attempt:11 waiting for isolate _startGrpc to check in
Attempt:12 waiting for isolate _startGrpc to check in

Here's the full copy of lib/main.dart file for reference:

/// Example code from: https://codingwithjoe.com/dart-fundamentals-isolates/
/// Flutter example code from: https://gist.github.com/jebright/a7086adc305615aa3a655c6d8bd90264
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:isolate';

import 'dart:ffi';

// import 'package:ffi/ffi.dart';

// -- Normal gRPC server type definitions --
typedef startgrpc_func = void Function();
typedef StartGrpc = void Function();

typedef stopgrpc_func = void Function();
typedef StopGrpc = void Function();

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  Isolate _isolate;
  bool _running = false;
  static int _counter = 0;
  String notification = "";
  ReceivePort _receivePort;

  void _start() async {
    _running = true;
    _receivePort = ReceivePort();
    _isolate = await Isolate.spawn(_startGrpc, _receivePort.sendPort);
    _receivePort.listen(_handleMessage, onDone: () {
      print("done!");
    });
  }

  static void _checkTimer(SendPort sendPort) async {
    Timer.periodic(new Duration(seconds: 1), (Timer t) {
      _counter++;
      String msg = 'notification ' + _counter.toString();
      print('SEND: ' + msg);
      sendPort.send(msg);
    });
  }

  static void _startGrpc(SendPort sendPort) async {
    // -- Normal gRPC server start code --
    final greeter = DynamicLibrary.open('assets/greeter.so');
    final void Function() startGrpc = greeter
        .lookup<NativeFunction<Void Function()>>('StartGrpc')
        .asFunction();
    String msg = "Started gRPC server...";
    sendPort.send(msg);
    startGrpc();
  }

  static void _stopGrpc() async {
    // -- Normal gRPC server stop code --
    final greeter = DynamicLibrary.open('assets/greeter.so');
    final void Function() stopGrpc = greeter
        .lookup<NativeFunction<Void Function()>>('StopGrpc')
        .asFunction();
    // String msg = "Stoped gRPC server...";
    // sendPort.send(msg);
    stopGrpc();
  }

  void _handleMessage(dynamic data) {
    print('RECEIVED: ' + data);
    setState(() {
      notification = data;
    });
  }

  void _stop() {
    if (_isolate != null) {
      setState(() {
        _running = false;
        notification = '';
      });
      _stopGrpc();
      _receivePort.close();
      _isolate.kill(priority: Isolate.immediate);
      _isolate = null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              notification,
            ),
          ],
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _running ? _stop : _start,
        tooltip: _running ? 'Timer stop' : 'Timer start',
        child: _running ? new Icon(Icons.stop) : new Icon(Icons.play_arrow),
      ),
    );
  }
}

If I first trigger StopGrpc() to stop gRPC server, and then close the application, the application exits without any issue.

Normal exit looks like this in debug console:

An Observatory debugger and profiler on Flutter test device is available at: http://127.0.0.1:50300/
Greet function was invoked with greeting:<first_name:"Satinder" last_name:"Grewal" > 
flutter: done!
go-flutter: closing application
Lost connection to device.
hover: App 'flutter_isolates' exited.
hover: Closing the flutter attach sub process..

So, I need to know where to put StopGrpc() function to trigger on application close/exit action.

Can someone please tell me how can I trigger a function to stop the server when exiting the application?

This is the go-grpc code that I'm compiling for this go-flutter application as a C library: https://github.com/satindergrewal/flutter-practice/blob/master/go_dart_ffi_c_shared/greet/greet_server/server.go

And this is the flutter code that I'm using to test flutter Isolates: https://github.com/satindergrewal/flutter-practice/tree/master/flutter_isolates

I have already asked for help from go-flutter and they pointed me to ask in flutter/flutter help channels.

Would really appreciate help on it.

Thanks, Satinder

satinder
  • 173
  • 3
  • 16

1 Answers1

2
@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(this);
}

void didChangeAppLifecycleState(AppLifecycleState state) {
  setState(() {
    if (AppLifecycleState.paused == state) {
      //Your function
    }
  });
}

@override
void dispose() {
  WidgetsBinding.instance.removeObserver(this);
  super.dispose();
}

enter link description here

enter link description here

Add an exit button to your application, if the user leaves the application with that button, trigger the function with that button.The above codes will be triggered if the user directly closes the application or keeps it in the background. Read more on the links

Raghim Najafov
  • 315
  • 3
  • 15