Analyze flutter_download_manager to learn how to manage, pause and cancel downloads

Preface

Downloading pictures or files in content applications, and application updates and upgrades in general applications are all classic download scenarios. Download is a basic and important module in the project.

Considering code logic reusability and labor cost, I have always wanted to implement a pure Dart-implemented download library as a technical reserve.

Recently, I discovered a pure Dart-implemented download library flutter_download_manager. Relatively speaking, it meets the needs in all aspects. It supports resume, pause, cancel and other functions that I value more. But some areas still need improvement.

Without further ado, let’s first briefly introduce this library.

Introduction to flutter_download_manager

Address: https://github.com/nabil6391/flutter_download_manager

Version: 0.5.4

Features:

  • Pure Dart implementation
  • Manage download tasks through url
  • Ability to notify about status and progress changes
  • Partial download function
  • queue download
  • Pause, cancel or resume downloads
  • Parallel file downloads (2 or can be changed)
  • Support batch download

Supported platforms: Linux | MacOS | Windows | Android | iOS

Instructions

Simply download a file

var dl = DownloadManager();
var url = "adasdad.com/asda.sdas";
dl.addDownload(url, "./test.sdas");

DownloadTask? task = dl.getDownload(url4);

task?.status.addListener(() {
  print(task.status.value);
});

task?.progress.addListener(() {
  print(task.progress.value);
});

await dl.whenDownloadComplete(url4);

Get download status

DownloadTask? task = dl.getDownload(url4);
task?.status.addListener(() {
  print(task.status.value);
});

Get download progress

DownloadTask? task = dl.getDownload(url4);
task?.progress.addListener(() {
  print(task.progress.value);
});

Wait for task to complete

DownloadTask? task = dl.getDownload(url4);
await task.whenDownloadComplete();

Cancel download task

var dl = DownloadManager();
dl.cancelDownload(url5);

Pause download task

var dl = DownloadManager();
dl.pauseDownload(url5);

Resume download task

var dl = DownloadManager();
dl.resumeDownload(url5);

Show results

Record_2023-02-24-18-20-47_082aea295e0e2b19157fadadca43d2cc.gif

Source code analysis

Class Diagram

Untitled.png

Task management class: DownloadManager

The entire core is similar to DownloadManager, and the abstraction of each download task is DownloadTask. The so-called Manager is of course responsible for managing these Tasks. So how to manage it? The free ones cannot be controlled. They can only be deployed if they are found first. The task handle is held through Map to achieve the purpose of "finding". Among them, _cache caches the status of each task in the memory in the form of <download URL, download task>; while _queue It is a newly added download task request. The relationship between the two will be discussed in detail later in the process.

Abstraction of tasks: DownloadTask

Let’s focus on the status and progress field design. Whether it is batch download or single task download, progress monitoring is not carried out through the traditional callback to download or addDownload, but uses the system’s ValueNotifier. The author considers this design because it is easier to organize the UI with the ValueListenerBuilder provided by the flutter system. (Does this design look more Dart?)

Task request abstraction: DownloadRequest

Let’s focus on cancelToken. This field plays a key role in pausing, canceling, and resuming download tasks. Like a kite that has been flown out, you can take it back when you want. How to take it back? Through the line, the function of this line is cancelToken. Kites are like task requests. The person flying the kite is the Manager, and the matter of flying the kite is the Task.

Each request must carry a cancelToken to facilitate request cancellation. (Can a kite without strings let you fly into the sky?)

No method stated

The method in the DownloadManager in the figure only writes the single-task download-related methods, and the batch-related methods are almost omitted, similar to (add | pause | cancel | resume | remove).BatchDownload, etc., and finally the single implementation method is executed through a loop.

Principle analysis

How to manage tasks

The code process will not be explained in detail here. To facilitate understanding, just take the common logic of doing things in life as an example. You can check the code implementation by yourself. It also follows this routine. First, there are two sets:

  • The task request list contains the things you want to do. If you have to define the status of each thing, it can be said to be "planning".

The subsequent abbreviation of task list refers to the request list.

  • Generally, the things in the task management list are not recorded, they are kept in the mind. During software development, PM the maintainer of this form.

Untitled 1.png

The general process for completing a task is as follows:

  1. Generate a task request to express your wishes.
  2. Query the task status in the task management table and determine whether it is actually eligible to be added to the request list.
  • Completed task : I have caught fish once 3 days ago. I can fish once a week at most. Return the task result directly. I reject this unrealistic idea and have no shame in adding it to the request list.
  • Unstarted tasks : If you haven’t played LoL for a week, you can add the game to the request list and update it to the task management list.
  • Unfinished task : 50% of the bricks moved last time will be moved next week. It depends on how you handle it at this time. If 50% of the bricks are still there, you can continue to move and add the task to the request list, starting from 50% until completed. If the bricks that have not been moved are piled up and you don’t want to continue coding, you can delete the record in the task management table and add a new task to the request list and management list.
  • New planned task : If there is no such record in the task management list, the new task will be re-added to the request list.
  1. Cyclically execute each task in the request list and update the status in the management list in a timely manner until the request list is empty.

The flow chart is as follows:

Untitled 2.png

How to implement pause, resume and cancel

The key is to control the cancelToken in DownloadRequest.

Pause task

Untitled 3.png

recovery task

Untitled 4.png

Cancel task

Untitled 5.png

Who are you kidding by pausing and canceling tasks?

It is generally understood that pause means that 50% was downloaded before, and downloading will continue from 50% after resumption; cancel means that 50% was downloaded before, and click resume to start over.

The pause and cancel logic are basically the same except for the update status. Are you fooling me?

Don't panic! Is there any processing during downloading?

The entire suspension implementation process is summarized through the above recovery implementation and the following download logic:

  1. When resuming downloading ③④⑤, a new CancelToken will be given to the paused url and re-added to the request list, and the self-traversal execution of the request list will be enabled.
  2. The self-traversal execution of the request list gives the opportunity to pause the task and re-execute it. The canceled task cannot be executed again (line 6 below).
  3. During the download process, if the file that has not been downloaded has been paused before, the breakpoint can be resumed by setting range:bytes in the header (line 29 below).

Untitled 6.png

pros and cons

advantage

  • Logic reuse: The Dart side supports pause, cancel, resume, and download processes. Generally, the download framework will be implemented using a bridge, which involves multi-terminal implementation and versatility issues, which is more labor-intensive. Either dio simply implements downloading without pausing, resuming, etc.
  • For task management, general applications are single-task downloads and there is no management process.
  • The code is simple, clear and highly readable, and the class abstraction is reasonable and consistent with a single responsibility.

shortcoming

  • The task management list only implements memory caching but not disk caching. If you exit and re-enter the application, nothing will happen.
  • The network library does not support extensions and relies too much on dio.

Preview: The next article will implement dio decoupling and network library expansion.

import 'package:dio/dio.dart';

class DownloadRequest {
  var cancelToken = CancelToken();
 }

------------------------------------------------
import 'package:dio/dio.dart';
class DownloadManager {
  var dio = Dio();

Future<void> download(String url, String savePath, cancelToken,
      {forceDownload = false}) async {
//...
if(fileExist){
}else(partialFileExist)
{
   var response = await dio.download(...);
}else{
   var response = await dio.download(...);
}

Summarize

Task management is reflected in the addition, deletion, modification and query of the list; breakpoint resume transmission is reflected in the range setting; task cancellation is simply realized by requesting library cancellation.

❤️This article was originally written by Programming Blackboard . Welcome to follow the public account of the same name. Original technical articles will be pushed out as soon as possible❤️

Guess you like

Origin blog.csdn.net/tingchan/article/details/129313624
Recommended