热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

使用Android的OkHttp包实现基于HTTP协议的文件上传下载

OkHttp(GitHub主页https:github.comsquareokhttp)是近来人气攀升的一款安卓第三方HTTP包,这里我们来讲解一下如何使用Android的OkHttp包实现基于HTTP协议的文件上传下载:

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  void upLoadFile(String actionUrl, String filePath, final ReqCallBack 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 
   */
  public void upLoadFile(String actionUrl, HashMap paramsMap, final ReqCallBack 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 
   */
  public  void upLoadFile(String actionUrl, HashMap paramsMap, final ReqProgressCallBack 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 
   * @return
   */
  public  RequestBody createProgressRequestBody(final MediaType contentType, final File file, final ReqProgressCallBack 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  void downLoadFile(String fileUrl, final String destFileDir, final ReqCallBack 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  void downLoadFile(String fileUrl, final String destFileDir, final ReqProgressCallBack 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 extends ReqCallBack{
  /**
   * 响应进度更新
   */
  void onProgress(long total, long current);
}
8.进度回调实现
  /**
   * 统一处理进度信息
   * @param total  总计大小
   * @param current 当前进度
   * @param callBack
   * @param 
   */
  private  void progressCallBack(final long total, final long current, final ReqProgressCallBack callBack) {
    okHttpHandler.post(new Runnable() {
      @Override
      public void run() {
        if (callBack != null) {
          callBack.onProgress(total, current);
        }
      }
    });
  }


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 本文介绍了求解gcdexgcd斐蜀定理的迭代法和递归法,并解释了exgcd的概念和应用。exgcd是指对于不完全为0的非负整数a和b,gcd(a,b)表示a和b的最大公约数,必然存在整数对x和y,使得gcd(a,b)=ax+by。此外,本文还给出了相应的代码示例。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 【MicroServices】【Arduino】装修甲醛检测,ArduinoDart甲醛、PM2.5、温湿度、光照传感器等,数据记录于SD卡,Python数据显示,UI5前台,微服务后台……
    这篇文章介绍了一个基于Arduino的装修甲醛检测项目,使用了ArduinoDart甲醛、PM2.5、温湿度、光照传感器等硬件,并将数据记录于SD卡,使用Python进行数据显示,使用UI5进行前台设计,使用微服务进行后台开发。该项目还在不断更新中,有兴趣的可以关注作者的博客和GitHub。 ... [详细]
author-avatar
手机用户2502894533
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有