downloading a large video with Dio download causes out of memory

Viewed 1072

I am trying to make a flutter app with downloading videos functionality from a url and videos are expected to be large (1 to 2 hours of 720p atleast).

I used Dio for this but it tries to store the complete video in RAM which causes the out of memory error. This is the code I used.

Any workarounds? or better solutions?

 Dio dio = Dio();
  dio
      .download(
        url,
        filePathAndName,
        onReceiveProgress: (count, total) {
       
          progressStream.add(count / total);
        },
      )
      .asStream()
      .listen((event) {
       
      })
      .onDone(() {
        Fluttertoast.showToast(msg: "Video downloaded");
       
      });

After a while it gives this exception : java.lang.OutOfMemoryError

1 Answers

Since it's a large file, I think it would be better to download your file using flutter_downloader plugin which also supports notifications and background mode

Init flutter downloader

WidgetsFlutterBinding.ensureInitialized();
await FlutterDownloader.initialize(
  debug: true // optional: set false to disable printing logs to console
);

Handle isolates

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. For 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]);
}

Download the file

final taskId = await FlutterDownloader.enqueue(
  url: 'your download link',
  savedDir: 'the path of directory where you want to save downloaded files',
  showNotification: true, // show download progress in status bar (for Android)
  openFileFromNotification: true, // click on notification to open downloaded file (for Android)
);
Related