SoFunction
Updated on 2025-04-11

Example of using Retrofit to download files and implement progress listening

1. Preface

Recently, I want to create a function to download files with progress bars. I looked around online and found that many of them were implemented based on OkHttpClient with the addition of interceptors. I personally think it is a bit complicated, so I still use the simplest method to implement it: monitor progress based on file writing.

2. Implementation steps

2.1 Designing a monitoring interface

Design the interface according to the requirements:

public interface DownloadListener {
  void onStart();//Download starts
  void onProgress(int progress);//Download progress
  void onFinish(String path);//Download completed
  void onFail(String errorInfo);//Download failed}

If you still need download speed, etc., you can design the interface and parameters yourself.

2.2 Writing a network interface service

public interface DownloadService {

  @Streaming
  @GET
  Call<ResponseBody> download(@Url String url);
}

It is basically the same as the normal interface writing method. It should be noted that the @Streaming annotation should be added.

By default, Retrofit will read all the server-side Response into memory before processing the results. If the server returns a very large file, it is easy to occur. The main function of using @Streaming is to write the bytes downloaded in real time to disk immediately without reading the entire file into memory.

2.3 Start network request

public class DownloadUtil {

  public static void download(String url, final String path, final DownloadListener downloadListener) {

    Retrofit retrofit = new ()
        .baseUrl("")
        //Get a thread through the thread pool and specify that callback runs in the child thread.        .callbackExecutor(())
        .build();

    DownloadService service = ();

    Call&lt;ResponseBody&gt; call = (url);
    (new Callback&lt;ResponseBody&gt;() {
      @Override
      public void onResponse(@NonNull Call&lt;ResponseBody&gt; call, @NonNull final Response&lt;ResponseBody&gt; response) {
        //Write Response to the disk, see the following analysis for details        //Note that this method is run in the child thread        writeResponseToDisk(path, response, downloadListener);
      }

      @Override
      public void onFailure(@NonNull Call&lt;ResponseBody&gt; call, @NonNull Throwable throwable) {
        ("Network Error~");
      }
    });
  }
}

In Retrofit, Callback runs in the main thread by default. If we write Response directly to disk, this operation will be run directly in the main thread, a NetworkOnMainThreadException will be reported. So it must be placed in the child thread to run.

So far, it is still a very normal network request. So, it's still very simple. The highlight of the following is here.

2.4 Monitoring download progress

private static void writeResponseToDisk(String path, Response&lt;ResponseBody&gt; response, DownloadListener downloadListener) {
    //Get input stream and total size from response    writeFileFromIS(new File(path), ().byteStream(), ().contentLength(), downloadListener);
  }

  private static int sBufferSize = 8192;

  //Write the input stream to the file  private static void writeFileFromIS(File file, InputStream is, long totalLength, DownloadListener downloadListener) {
    //Start download    ();

    //Create a file    if (!()) {
      if (!().exists())
        ().mkdir();
      try {
        ();
      } catch (IOException e) {
        ();
        ("createNewFile IOException");
      }
    }

    OutputStream os = null;
    long currentLength = 0;
    try {
      os = new BufferedOutputStream(new FileOutputStream(file));
      byte data[] = new byte[sBufferSize];
      int len;
      while ((len = (data, 0, sBufferSize)) != -1) {
        (data, 0, len);
        currentLength += len;
        //Calculate the current download progress        ((int) (100 * currentLength / totalLength));
      }
      //Download is completed and return to the saved file path      (());
    } catch (IOException e) {
      ();
      ("IOException");
    } finally {
      try {
        ();
      } catch (IOException e) {
        ();
      }
      try {
        if (os != null) {
          ();
        }
      } catch (IOException e) {
        ();
      }
    }
  }

Therefore, it is actually to realize the monitoring of progress by listening to the file writing.

2.5 Use Examples

String url = "";
      String path = "";
      (url, path, new DownloadListener() {
        @Override
        public void onStart() {
          //Run in child thread        }

        @Override
        public void onProgress(int progress) {
          //Run in child thread        }

        @Override
        public void onFinish(String path) {
          //Run in child thread        }

        @Override
        public void onFail(String errorInfo) {
          //Run in child thread        }
      });

Note that the above callbacks are all run in child threads. If you need to update the UI and other operations, you can use Handler and so on to update it.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.