SoFunction
Updated on 2025-03-11

Using Android's OkHttp package to achieve file upload and download based on HTTP protocol

The basics of HTTP connections for OkHttp
Although only a URL is required to provide when sending HTTP requests using OkHttp, OkHttp needs to consider 3 different elements in its implementation to determine the actual HTTP connection to the HTTP server. The purpose of this is to achieve optimal performance.
The first element to consider is the URL itself. The URL gives the path to the resource to be accessed. For example, the URL corresponds to the HTTP document on Baidu homepage. The most important part of a URL is the pattern used when accessing, i.e. HTTP or HTTPS. This determines whether OkHttp establishes a plaintext HTTP connection or an encrypted HTTPS connection.
The second element is the address of the HTTP server, such as . Each address has a corresponding configuration, including port number, HTTPS connection settings and network transmission protocol. URLs on the same address can share the same underlying TCP socket connection. There can be significant performance improvements through shared connections. OkHttp provides a connection pool to multiplex connections.
The third element is the route used when connecting to the HTTP server. The route includes the IP address of the specific connection (discovered through DNS queries) and the proxy server used. For HTTPS connections, the TLS version used for communication negotiation is also included. For the same address, there may be multiple different routes. OkHttp will automatically attempt an alternative route when an access error is encountered.
When requesting a URL through OkHttp, OkHttp first obtains address information from the URL, and then obtains the connection based on the address from the connection pool. If no connection is found in the connection pool, select a route to try the connection. When trying to connect, you need to use DNS query to get the server's IP address, and you will also use information such as proxy server and TLS version. When the actual connection is established, OkHttp sends an HTTP request and gets the response. When there is a problem with the connection, OkHttp will automatically select another route to try. This allows OkHttp to automatically handle possible network problems. After successfully obtaining the response to the HTTP request, the current connection will be put back into the connection pool and provided to subsequent requests for multiplexing. The connection pool periodically closes idle connections to free up resources.

File upload and download examples:
1. Upload the file without parameters

  /**
    * Upload file
    * @param actionUrl interface address
    * @param filePath Local file address
    */
  public <T> void upLoadFile(String actionUrl, String filePath, final ReqCallBack<T> callBack) {
    //Complete the request address    String requestUrl = ("%s/%s", BASE_URL, actionUrl);
    //Create File    File file = new File(filePath);
    //Create RequestBody    RequestBody body = (MEDIA_OBJECT_STREAM, file);
    //Create Request    final Request request = new ().url(requestUrl).post(body).build();
    final Call call = ().writeTimeout(50, ).build().newCall(request);
    (new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        (TAG, ());
        failedCallBack("Upload failed", callBack);
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
        if (()) {
          String string = ().string();
          (TAG, "response ----->" + string);
          successCallBack((T) string, callBack);
        } else {
          failedCallBack("Upload failed", callBack);
        }
      }
    });
  }

2. Upload file with parameters

/**
    *Upload file
    * @param actionUrl interface address
    * @param paramsMap parameters
    * @param callBack callback
    * @param <T>
    */
  public &lt;T&gt;void upLoadFile(String actionUrl, HashMap&lt;String, Object&gt; paramsMap, final ReqCallBack&lt;T&gt; callBack) {
    try {
      //Complete the request address      String requestUrl = ("%s/%s", upload_head, actionUrl);
       builder = new ();
      //Set type      ();
      //Add parameters      for (String key : ()) {
        Object object = (key);
        if (!(object instanceof File)) {
          (key, ());
        } else {
          File file = (File) object;
          (key, (), (null, file));
        }
      }
      //Create RequestBody      RequestBody body = ();
      //Create Request      final Request request = new ().url(requestUrl).post(body).build();
      //Set parameters separately, such as reading timeout time      final Call call = ().writeTimeout(50, ).build().newCall(request);
      (new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
          (TAG, ());
          failedCallBack("Upload failed", callBack);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
          if (()) {
            String string = ().string();
            (TAG, "response -----&gt;" + string);
            successCallBack((T) string, callBack);
          } else {
            failedCallBack("Upload failed", callBack);
          }
        }
      });
    } catch (Exception e) {
      (TAG, ());
    }
  }

3. Upload files with parameters and progress

 /**
    *Upload file
    * @param actionUrl interface address
    * @param paramsMap parameters
    * @param callBack callback
    * @param <T>
    */
  public &lt;T&gt; void upLoadFile(String actionUrl, HashMap&lt;String, Object&gt; paramsMap, final ReqProgressCallBack&lt;T&gt; callBack) {
    try {
      //Complete the request address      String requestUrl = ("%s/%s", upload_head, actionUrl);
       builder = new ();
      //Set type      ();
      //Add parameters      for (String key : ()) {
        Object object = (key);
        if (!(object instanceof File)) {
          (key, ());
        } else {
          File file = (File) object;
          (key, (), createProgressRequestBody(MEDIA_OBJECT_STREAM, file, callBack));
        }
      }
      //Create RequestBody      RequestBody body = ();
      //Create Request      final Request request = new ().url(requestUrl).post(body).build();
      final Call call = ().writeTimeout(50, ).build().newCall(request);
      (new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
          (TAG, ());
          failedCallBack("Upload failed", callBack);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
          if (()) {
            String string = ().string();
            (TAG, "response -----&gt;" + string);
            successCallBack((T) string, callBack);
          } else {
            failedCallBack("Upload failed", callBack);
          }
        }
      });
    } catch (Exception e) {
      (TAG, ());
    }
  }

4. Create a RequestBody with Progress

 /**
    * Create a RequestBody with progress
    * @param contentType MediaType
    * @param file Prepare uploaded file
    * @param callBack callback
    * @param <T>
    * @return
    */
  public &lt;T&gt; RequestBody createProgressRequestBody(final MediaType contentType, final File file, final ReqProgressCallBack&lt;T&gt; callBack) {
    return new RequestBody() {
      @Override
      public MediaType contentType() {
        return contentType;
      }

      @Override
      public long contentLength() {
        return ();
      }

      @Override
      public void writeTo(BufferedSink sink) throws IOException {
        Source source;
        try {
          source = (file);
          Buffer buf = new Buffer();
          long remaining = contentLength();
          long current = 0;
          for (long readCount; (readCount = (buf, 2048)) != -1; ) {
            (buf, readCount);
            current += readCount;
            (TAG, "current------&gt;" + current);
            progressCallBack(remaining, current, callBack);
          }
        } catch (Exception e) {
          ();
        }
      }
    };
  }

5. Download without progress file

 /**
    * Download the file
    * @param fileUrl file url
    * @param destFileDir Storage target directory
    */
  public &lt;T&gt; void downLoadFile(String fileUrl, final String destFileDir, final ReqCallBack&lt;T&gt; callBack) {
    final String fileName = (fileUrl);
    final File file = new File(destFileDir, fileName);
    if (()) {
      successCallBack((T) file, callBack);
      return;
    }
    final Request request = new ().url(fileUrl).build();
    final Call call = (request);
    (new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        (TAG, ());
        failedCallBack("Download failed", callBack);
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
        InputStream is = null;
        byte[] buf = new byte[2048];
        int len = 0;
        FileOutputStream fos = null;
        try {
          long total = ().contentLength();
          (TAG, "total------&gt;" + total);
          long current = 0;
          is = ().byteStream();
          fos = new FileOutputStream(file);
          while ((len = (buf)) != -1) {
            current += len;
            (buf, 0, len);
            (TAG, "current------&gt;" + current);
          }
          ();
          successCallBack((T) file, callBack);
        } catch (IOException e) {
          (TAG, ());
          failedCallBack("Download failed", callBack);
        } finally {
          try {
            if (is != null) {
              ();
            }
            if (fos != null) {
              ();
            }
          } catch (IOException e) {
            (TAG, ());
          }
        }
      }
    });
  }

6. Download progress file

 /**
    * Download the file
    * @param fileUrl file url
    * @param destFileDir Storage target directory
    */
  public &lt;T&gt; void downLoadFile(String fileUrl, final String destFileDir, final ReqProgressCallBack&lt;T&gt; callBack) {
    final String fileName = (fileUrl);
    final File file = new File(destFileDir, fileName);
    if (()) {
      successCallBack((T) file, callBack);
      return;
    }
    final Request request = new ().url(fileUrl).build();
    final Call call = (request);
    (new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        (TAG, ());
        failedCallBack("Download failed", callBack);
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
        InputStream is = null;
        byte[] buf = new byte[2048];
        int len = 0;
        FileOutputStream fos = null;
        try {
          long total = ().contentLength();
          (TAG, "total------&gt;" + total);
          long current = 0;
          is = ().byteStream();
          fos = new FileOutputStream(file);
          while ((len = (buf)) != -1) {
            current += len;
            (buf, 0, len);
            (TAG, "current------&gt;" + current);
            progressCallBack(total, current, callBack);
          }
          ();
          successCallBack((T) file, callBack);
        } catch (IOException e) {
          (TAG, ());
          failedCallBack("Download failed", callBack);
        } finally {
          try {
            if (is != null) {
              ();
            }
            if (fos != null) {
              ();
            }
          } catch (IOException e) {
            (TAG, ());
          }
        }
      }
    });
  }

7. Interface implementation
public interface ReqProgressCallBack&lt;T&gt; extends ReqCallBack&lt;T&gt;{
  /**
    * Response progress update
    */
  void onProgress(long total, long current);
}
8. Progress callback implementation
  /**
    * Unified processing progress information
    * @param total Total size
    * @param current current progress
    * @param callBack
    * @param <T>
    */
  private &lt;T&gt; void progressCallBack(final long total, final long current, final ReqProgressCallBack&lt;T&gt; callBack) {
    (new Runnable() {
      @Override
      public void run() {
        if (callBack != null) {
          (total, current);
        }
      }
    });
  }