skip to Main Content

I am running a test on using isolate to call function, below is my code

import 'dart:isolate';

import 'package:flutter/material.dart';

void main() async {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final result = await startDownloadUsingRunMethod();
          print('Factorial result: $result');
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }


  Future<String> startDownloadUsingRunMethod() async {
    final imageData = await Isolate.run(_readAndParseJsonWithoutIsolateLogic);
    return imageData;
  }

  Future<String> _readAndParseJsonWithoutIsolateLogic() async {
    await Future.delayed(const Duration(seconds: 2));
    return 'this is downloaded data';
  }
}

everytime when I tap on my floatingActionButton to run the function I will get the error below

E/flutter ( 9611): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Illegal argument in isolate message: object is unsendable – Library:’dart:async’ Class: _AsyncCompleter@4048458 (see restrictions listed at SendPort.send() documentation for more information)

anyone know what cause these issues?

2

Answers


  1. I see you are encountering because you are trying to send a non-sendable object (an async completer) to an isolate, which is not allowed. you need to modify the code to fix that issue. In your case, you can use the compute function provided by Flutter to run your _readAndParseJsonWithoutIsolateLogic function in a separate isolate. i already modified and updated your code, please use this below code, hope it will solve your problem.

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.deepPurple,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    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> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      Future<String> _readAndParseJsonWithoutIsolateLogic() async {
        await Future.delayed(const Duration(seconds: 2));
        return 'this is downloaded data';
      }
    
      Future<void> _startDownloadUsingCompute() async {
        final result = await compute<String, String>(_readAndParseJsonWithoutIsolateLogic, '');
        print('Download result: $result');
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                const Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.headline6,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              _startDownloadUsingCompute();
            },
            tooltip: 'Download',
            child: const Icon(Icons.cloud_download),
          ),
        );
      }
    }
    
    Login or Signup to reply.
  2. Isolate.run is used for isolates, which run in a separate isolate and do not support async/await operations directly.

    To fix this issue, you can use Isolate.spawn to run a function in a separate isolate and then use a ReceivePort to communicate between the main isolate and the spawned isolate. Here’s how you can modify your code to achieve this:

    floatingActionButton: FloatingActionButton(
            onPressed: () async {
              final result = await startDownloadUsingSpawn();
              print('Download result: $result');
            },
            tooltip: 'Download',
            child: const Icon(Icons.download),
          ),
        );
    
    Future<String> startDownloadUsingSpawn() async {
        final receivePort = ReceivePort();
        await Isolate.spawn(_readAndParseJsonWithoutIsolateLogic, receivePort.sendPort);
    
        final completer = Completer<String>();
        receivePort.listen((data) {
          completer.complete(data);
          receivePort.close();
        });
    
        return completer.future;
      }
    
    static void _readAndParseJsonWithoutIsolateLogic(SendPort sendPort) async {
        await Future.delayed(const Duration(seconds: 2));
        final result = 'This is downloaded data';
        sendPort.send(result);
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search