Android file download - Multi file multi thread breakpoint Download

Posted by InO on Wed, 17 Nov 2021 10:46:48 +0100

1. Preface

In my previous blog, I spent a few days doing a case of multi-threaded download, and tried to package it into my own wheel library. For example:

The final project address is:

However, due to network reasons, Github is almost inaccessible on my side. So these days, they began to turn to Gitee, a domestic warehouse.

I accidentally found that there are many open source projects in Gitee, such as this one page.

So I decided to find some Android file download related projects on Gitee. Understand other people's ideas, and then continue to rewrite the previous project.

Then found the item: zhangdcyf / MulDownload

I'll probably look at this project and make a simple record.

2. Learn MulDownload

First, you need to understand how to get these UML class diagrams through classes in Android studio. For the introduction of class diagram, please refer to: Introduction to PlantUML

On previous Blogs: UML diagrams and their use cases This article briefly introduces the relationships in some basic class diagrams. Later, we will continue to briefly introduce the relationships in UML diagrams in this blog according to the content of this website and consulting some materials.

You can refer to the article on how to get these UML class diagrams in Android studio Android studio UML diagram generation . I will not repeat the introduction here.

Then you can get the structure of this MulDownload as follows:

Take a look at the code of this project and make a simple analysis of the above figure:

In other words, the final core method is actually in the internal class DownloadRunnable of DownloadManagerController. Here, copy the implementation of this class:

 * Enable download (when there is a list download)
 * @param mData data source
 * @param downloadPath Download path
 * @param filePath     File storage path
 * @param fileName     File name
 * @param position     Which number is downloading
public void download(Object mData, String downloadPath, String filePath, String fileName, int position, OnProgressListener onProgressListener) {
    if (TextUtils.isEmpty(filePath)) {
        Log.d(TAG, "please inti filepath");

    DownloadBean mDownloadBean = DownloadBeanManager.getInstance().get(fileName);
    if (null != mDownloadBean) {
        // Can the same file be downloaded repeatedly
        if (DownloadProxy.obtain().getConfigBean().isReset()) {
        } else {
            if (!TextUtils.isEmpty(DownloadProxy.obtain().getConfigBean().getSubmit())) {
                        , DownloadProxy.obtain().getConfigBean().getSubmit(), Toast.LENGTH_SHORT).show();

    mExecutorService.execute(new DownloadRunnable(mData, downloadPath, filePath, fileName, position, onProgressListener));

private class DownloadRunnable implements Runnable {
    private Object mData;
    private String downloadPath;
    private String filePath;
    private String fileName;
    private int position;
    private OnProgressListener onProgressListener;

    public DownloadRunnable(Object mData, String downloadPath, String filePath, String fileName, int position, OnProgressListener onProgressListener) {
        this.mData = mData;
        this.downloadPath = downloadPath;
        this.filePath = filePath;
        this.fileName = fileName;
        this.position = position;
        this.onProgressListener = onProgressListener;

    public void run() {
        Log.i(TAG, downloadPath);
        //Create download request
        DownloadManager.Request down = new DownloadManager.Request(Uri.parse(downloadPath));
        //Set the allowed network type. Here, both mobile network and wifi can be used
        //Background download
                ? DownloadManager.Request.VISIBILITY_VISIBLE : DownloadManager.Request.VISIBILITY_HIDDEN);
        //Display the download interface
        //Set the file storage location after downloading
        down.setDestinationInExternalPublicDir(filePath, fileName);
        //Queue download requests
        DownloadBeanManager.getInstance().save(new DownloadBean(onProgressListener, fileName,, position, mData));

As can be seen from the purchased code, after simply judging whether to download repeatedly in the download method, this task is directly added to a thread pool, m executorservice.

Therefore, the specific execution is the run method in the DownloadRunnable class.

It's not difficult to find here. In fact, it is a simple download of files using Android's DownloadManager.

When the overall code flow comes down, I don't see any operations related to file breakpoint continuation, multi-threaded download, etc. Just pull the whole download package to a more reasonable structure. Because files are added to the download thread pool, the problem of multi file download can be handled here.

The overall highlight is that the download is decoupled, which is really worth learning.

Overall, I didn't achieve the desired results. However, the project is reconstructed according to the idea of the project. Thought is really good.

3. Imitation

According to MulDownload's subcontracting idea Previous projects Refactoring. Here, the single thread breakpoint download is not moved. Here, the multi thread breakpoint download version is directly modified. Moreover, the logic stored under the needs to be modified to support multi file and multi-threaded breakpoint download. The test results are as follows, and the expected results are achieved:

In order to realize multi file breakpoint download, you need to use a structure similar to map < URL, record > to record the downloaded data range of each thread of each file.

  • Use DownloadProgressHelper to store the download record of each file according to the download url in the format of map < string, long [] >. The array of each long type stores the current download data location of each thread of the file.
  • For the download progress of a single file, count all the data sizes of the above long type array.
  • In order to continue downloading from the previous location next time, the download record is stored in the SharedPreferences file, specifically in the SharedPreferencesHelper class. It is specified here that the Set is stored in the SP file as Set < String > type. Because the Set is unordered, it is unordered, so it cannot be identified by subscript. Therefore, when storing strings, use index#record to identify them. Keep consistent access. At the same time, it should be noted that multi threads need lock control.
  • In the process of requesting download, first use HttpURLConnection to request once to obtain the file size. First, judge whether the file size of the local download directory is consistent with that requested by the server. If it is consistent, there is no need to download. Otherwise, according to the defined number and size of threads, calculate the data range required by each thread, and then each thread requests the data of its own data range.

As for the rest of the details, they were also introduced in the previous article, and will not be repeated here. The package structure is:

Corresponding address: android-file-down-up-loader-learn/ mylibrary2

4. Postscript

This is just a simple refactoring. In the future, we will continue to find other people's projects and continue to package.

Topics: Java Android