Search code examples
flutterdartdio

downloading a large video with Dio download causes out of memory


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


Solution

  • 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)
    );