Calling a UI method from Isolate listen method in Flutter throws exception

2,919

check important note here

Important note: your UI is rendered in the main isolate, while download events come from a background isolate (in other words, codes in callback are run in the background isolate), so you have to handle the communication between two isolates.

Check Example,

ReceivePort _port = ReceivePort();

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

    IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
    _port.listen((dynamic data) {
        String id = data[0];
        DownloadTaskStatus status = data[1];
        int progress = data[2];
        setState((){ });
    });

    FlutterDownloader.registerCallback(downloadCallback);
}

@override
void dispose() {
    IsolateNameServer.removePortNameMapping('downloader_send_port');
    super.dispose();
}

static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
    final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port');
    send.send([id, status, progress]);
}
Share:
2,919
AVEbrahimi
Author by

AVEbrahimi

Untying an impossibly tangled knot is actually possible. For every problem, there is a solution. And I am just one who is interested in untying and solving, that's it :)

Updated on December 15, 2022

Comments

  • AVEbrahimi
    AVEbrahimi over 1 year

    I tried to use ovprogresshud (https://pub.dev/packages/ovprogresshud) to show download progress. I used flutter_downloader (https://pub.dev/packages/flutter_downloader) for download.

    I try to update progress via an Isolate, but receive errors. (If I call Progresshud.showWithStatusdirectly in my code, say before download, it works)

    My code:

    ReceivePort _port = ReceivePort();
    ...
    
    IsolateNameServer.registerPortWithName(
            _port.sendPort, 'downloader_send_port');
    _port.listen(
          (dynamic data) {
            String id = data[0];
            DownloadTaskStatus status = data[1];
            int progress = data[2];
            if (status == DownloadTaskStatus.complete) {
            } else if (status == DownloadTaskStatus.running) {
              Progresshud.showWithStatus("%$progress Downloaded");
            }
          },
          onDone: () {
            checkIfDictionaryUnzipped(DBFilePath);
          },
          onError: (error) {},
        );
    

    The error I receive:

    Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'android.view.ViewParent android.view.ViewGroup.getParent()' on a null object reference, null)
    E/flutter (29114): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:569:7)
    E/flutter (29114): #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:321:33)
    E/flutter (29114): <asynchronous suspension>
    E/flutter (29114): #2      Progresshud.showWithStatus (package:ovprogresshud/progresshud.dart:18:27)
    E/flutter (29114): <asynchronous suspension>
    ....
    
  • AVEbrahimi
    AVEbrahimi over 4 years
    I did same and called Progresshud.showWithStatus in listen but it throws exception
  • Abhay Koradiya
    Abhay Koradiya over 4 years
    do not call Progresshud.showWithStatus. Only rebuild using setstate. and show that progress in build.
  • AVEbrahimi
    AVEbrahimi over 4 years
    aha, so I should not use ovprogresshud? or I use something like ValueNotifier::addListener
  • Abhay Koradiya
    Abhay Koradiya over 4 years
    you can but you need to show it only from Build method.