Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 使用Android的OkHttp包實現基於HTTP協議的文件上傳下載

使用Android的OkHttp包實現基於HTTP協議的文件上傳下載

編輯:關於Android編程

OkHttp的HTTP連接基礎
雖然在使用 OkHttp 發送 HTTP 請求時只需要提供 URL 即可,OkHttp 在實現中需要綜合考慮 3 種不同的要素來確定與 HTTP 服務器之間實際建立的 HTTP 連接。這樣做的目的是為了達到最佳的性能。
首先第一個考慮的要素是 URL 本身。URL 給出了要訪問的資源的路徑。比如 URL http://www.baidu.com 所對應的是百度首頁的 HTTP 文檔。在 URL 中比較重要的部分是訪問時使用的模式,即 HTTP 還是 HTTPS。這會確定 OkHttp 所建立的是明文的 HTTP 連接,還是加密的 HTTPS 連接。
第二個要素是 HTTP 服務器的地址,如 baidu.com。每個地址都有對應的配置,包括端口號,HTTPS 連接設置和網絡傳輸協議。同一個地址上的 URL 可以共享同一個底層 TCP 套接字連接。通過共享連接可以有顯著的性能提升。OkHttp 提供了一個連接池來復用連接。
第三個要素是連接 HTTP 服務器時使用的路由。路由包括具體連接的 IP 地址(通過 DNS 查詢來發現)和所使用的代理服務器。對於 HTTPS 連接還包括通訊協商時使用的 TLS 版本。對於同一個地址,可能有多個不同的路由。OkHttp 在遇到訪問錯誤時會自動嘗試備選路由。
當通過 OkHttp 來請求某個 URL 時,OkHttp 首先從 URL 中得到地址信息,再從連接池中根據地址來獲取連接。如果在連接池中沒有找到連接,則選擇一個路由來嘗試連接。嘗試連接需要通過 DNS 查詢來得到服務器的 IP 地址,也會用到代理服務器和 TLS 版本等信息。當實際的連接建立之後,OkHttp 發送 HTTP 請求並獲取響應。當連接出現問題時,OkHttp 會自動選擇另外的路由進行嘗試。這使得 OkHttp 可以自動處理可能出現的網絡問題。當成功獲取到 HTTP 請求的響應之後,當前的連接會被放回到連接池中,提供給後續的請求來復用。連接池會定期把閒置的連接關閉以釋放資源。

文件上傳和下載實例:
1.不帶參數上傳文件

  /**
   * 上傳文件
   * @param actionUrl 接口地址
   * @param filePath 本地文件地址
   */
  public <T> void upLoadFile(String actionUrl, String filePath, final ReqCallBack<T> callBack) {
    //補全請求地址
    String requestUrl = String.format("%s/%s", BASE_URL, actionUrl);
    //創建File
    File file = new File(filePath);
    //創建RequestBody
    RequestBody body = RequestBody.create(MEDIA_OBJECT_STREAM, file);
    //創建Request
    final Request request = new Request.Builder().url(requestUrl).post(body).build();
    final Call call = mOkHttpClient.newBuilder().writeTimeout(50, TimeUnit.SECONDS).build().newCall(request);
    call.enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        Log.e(TAG, e.toString());
        failedCallBack("上傳失敗", callBack);
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful()) {
          String string = response.body().string();
          Log.e(TAG, "response ----->" + string);
          successCallBack((T) string, callBack);
        } else {
          failedCallBack("上傳失敗", callBack);
        }
      }
    });
  }

2.帶參數上傳文件

/**
   *上傳文件
   * @param actionUrl 接口地址
   * @param paramsMap 參數
   * @param callBack 回調
   * @param <T>
   */
  public <T>void upLoadFile(String actionUrl, HashMap<String, Object> paramsMap, final ReqCallBack<T> callBack) {
    try {
      //補全請求地址
      String requestUrl = String.format("%s/%s", upload_head, actionUrl);
      MultipartBody.Builder builder = new MultipartBody.Builder();
      //設置類型
      builder.setType(MultipartBody.FORM);
      //追加參數
      for (String key : paramsMap.keySet()) {
        Object object = paramsMap.get(key);
        if (!(object instanceof File)) {
          builder.addFormDataPart(key, object.toString());
        } else {
          File file = (File) object;
          builder.addFormDataPart(key, file.getName(), RequestBody.create(null, file));
        }
      }
      //創建RequestBody
      RequestBody body = builder.build();
      //創建Request
      final Request request = new Request.Builder().url(requestUrl).post(body).build();
      //單獨設置參數 比如讀取超時時間
      final Call call = mOkHttpClient.newBuilder().writeTimeout(50, TimeUnit.SECONDS).build().newCall(request);
      call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
          Log.e(TAG, e.toString());
          failedCallBack("上傳失敗", callBack);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
          if (response.isSuccessful()) {
            String string = response.body().string();
            Log.e(TAG, "response ----->" + string);
            successCallBack((T) string, callBack);
          } else {
            failedCallBack("上傳失敗", callBack);
          }
        }
      });
    } catch (Exception e) {
      Log.e(TAG, e.toString());
    }
  }

3.帶參數帶進度上傳文件

 /**
   *上傳文件
   * @param actionUrl 接口地址
   * @param paramsMap 參數
   * @param callBack 回調
   * @param <T>
   */
  public <T> void upLoadFile(String actionUrl, HashMap<String, Object> paramsMap, final ReqProgressCallBack<T> callBack) {
    try {
      //補全請求地址
      String requestUrl = String.format("%s/%s", upload_head, actionUrl);
      MultipartBody.Builder builder = new MultipartBody.Builder();
      //設置類型
      builder.setType(MultipartBody.FORM);
      //追加參數
      for (String key : paramsMap.keySet()) {
        Object object = paramsMap.get(key);
        if (!(object instanceof File)) {
          builder.addFormDataPart(key, object.toString());
        } else {
          File file = (File) object;
          builder.addFormDataPart(key, file.getName(), createProgressRequestBody(MEDIA_OBJECT_STREAM, file, callBack));
        }
      }
      //創建RequestBody
      RequestBody body = builder.build();
      //創建Request
      final Request request = new Request.Builder().url(requestUrl).post(body).build();
      final Call call = mOkHttpClient.newBuilder().writeTimeout(50, TimeUnit.SECONDS).build().newCall(request);
      call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
          Log.e(TAG, e.toString());
          failedCallBack("上傳失敗", callBack);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
          if (response.isSuccessful()) {
            String string = response.body().string();
            Log.e(TAG, "response ----->" + string);
            successCallBack((T) string, callBack);
          } else {
            failedCallBack("上傳失敗", callBack);
          }
        }
      });
    } catch (Exception e) {
      Log.e(TAG, e.toString());
    }
  }

4.創建帶進度RequestBody

 /**
   * 創建帶進度的RequestBody
   * @param contentType MediaType
   * @param file 准備上傳的文件
   * @param callBack 回調
   * @param <T>
   * @return
   */
  public <T> RequestBody createProgressRequestBody(final MediaType contentType, final File file, final ReqProgressCallBack<T> callBack) {
    return new RequestBody() {
      @Override
      public MediaType contentType() {
        return contentType;
      }

      @Override
      public long contentLength() {
        return file.length();
      }

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

5.不帶進度文件下載  

 /**
   * 下載文件
   * @param fileUrl 文件url
   * @param destFileDir 存儲目標目錄
   */
  public <T> void downLoadFile(String fileUrl, final String destFileDir, final ReqCallBack<T> callBack) {
    final String fileName = MD5.encode(fileUrl);
    final File file = new File(destFileDir, fileName);
    if (file.exists()) {
      successCallBack((T) file, callBack);
      return;
    }
    final Request request = new Request.Builder().url(fileUrl).build();
    final Call call = mOkHttpClient.newCall(request);
    call.enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        Log.e(TAG, e.toString());
        failedCallBack("下載失敗", 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 = response.body().contentLength();
          Log.e(TAG, "total------>" + total);
          long current = 0;
          is = response.body().byteStream();
          fos = new FileOutputStream(file);
          while ((len = is.read(buf)) != -1) {
            current += len;
            fos.write(buf, 0, len);
            Log.e(TAG, "current------>" + current);
          }
          fos.flush();
          successCallBack((T) file, callBack);
        } catch (IOException e) {
          Log.e(TAG, e.toString());
          failedCallBack("下載失敗", callBack);
        } finally {
          try {
            if (is != null) {
              is.close();
            }
            if (fos != null) {
              fos.close();
            }
          } catch (IOException e) {
            Log.e(TAG, e.toString());
          }
        }
      }
    });
  }

6.帶進度文件下載

 /**
   * 下載文件
   * @param fileUrl 文件url
   * @param destFileDir 存儲目標目錄
   */
  public <T> void downLoadFile(String fileUrl, final String destFileDir, final ReqProgressCallBack<T> callBack) {
    final String fileName = MD5.encode(fileUrl);
    final File file = new File(destFileDir, fileName);
    if (file.exists()) {
      successCallBack((T) file, callBack);
      return;
    }
    final Request request = new Request.Builder().url(fileUrl).build();
    final Call call = mOkHttpClient.newCall(request);
    call.enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        Log.e(TAG, e.toString());
        failedCallBack("下載失敗", 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 = response.body().contentLength();
          Log.e(TAG, "total------>" + total);
          long current = 0;
          is = response.body().byteStream();
          fos = new FileOutputStream(file);
          while ((len = is.read(buf)) != -1) {
            current += len;
            fos.write(buf, 0, len);
            Log.e(TAG, "current------>" + current);
            progressCallBack(total, current, callBack);
          }
          fos.flush();
          successCallBack((T) file, callBack);
        } catch (IOException e) {
          Log.e(TAG, e.toString());
          failedCallBack("下載失敗", callBack);
        } finally {
          try {
            if (is != null) {
              is.close();
            }
            if (fos != null) {
              fos.close();
            }
          } catch (IOException e) {
            Log.e(TAG, e.toString());
          }
        }
      }
    });
  }

7.接口ReqProgressCallBack.java實現
public interface ReqProgressCallBack<T> extends ReqCallBack<T>{
  /**
   * 響應進度更新
   */
  void onProgress(long total, long current);
}
8.進度回調實現
  /**
   * 統一處理進度信息
   * @param total  總計大小
   * @param current 當前進度
   * @param callBack
   * @param <T>
   */
  private <T> void progressCallBack(final long total, final long current, final ReqProgressCallBack<T> callBack) {
    okHttpHandler.post(new Runnable() {
      @Override
      public void run() {
        if (callBack != null) {
          callBack.onProgress(total, current);
        }
      }
    });
  }

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved