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

RxJava+Retrofit+OkHttp实现文件上传

背景 在实际运用中上传是一个必不可少的功能,所以我们在封装二的基础上加入上传的功能,同时需要附带上传进度! 效果 实现 1.定义

背景

在实际运用中上传是一个必不可少的功能,所以我们在封装二的基础上加入上传的功能,同时需要附带上传进度!

效果

实现

1.定义service接口

注意:Multipart是指定大文件上传过程中的标示,一般上传图片的过程中我们需要附带信息,所以我们需要用到@part指定传递的数值,MultipartBody.Part是指定传递的文件;

  /*上传文件*/
  @Multipart
  @POST("AppYuFaKu/uploadHeadImg")
  Observable> uploadImage(@Part("uid") RequestBody uid, @Part("auth_key") RequestBody auth_key,@Part MultipartBody.Part file);

2.加入进度条

retrofit是基于okhttp的处理,所以我们可以自定义RequestBody,复写writeTo(BufferedSink sink)方法,得到传递的进度数据

public class ProgressRequestBody extends RequestBody {
  //实际的待包装请求体
  private final RequestBody requestBody;
  //进度回调接口
  private final UploadProgressListener progressListener;
  //包装完成的BufferedSink
  private BufferedSink bufferedSink;

  public ProgressRequestBody(RequestBody requestBody, UploadProgressListener progressListener) {
    this.requestBody = requestBody;
    this.progressListener = progressListener;
  }
  /**
   * 重写调用实际的响应体的contentType
   * @return MediaType
   */
  @Override
  public MediaType contentType() {
    return requestBody.contentType();
  }
  /**
   * 重写调用实际的响应体的contentLength
   * @return contentLength
   * @throws IOException 异常
   */
  @Override
  public long contentLength() throws IOException {
    return requestBody.contentLength();
  }
  /**
   * 重写进行写入
   * @param sink BufferedSink
   * @throws IOException 异常
   */
  @Override
  public void writeTo(BufferedSink sink) throws IOException {
    if (null == bufferedSink) {
      bufferedSink = Okio.buffer(sink(sink));
    }
    requestBody.writeTo(bufferedSink);
    //必须调用flush,否则最后一部分数据可能不会被写入
    bufferedSink.flush();
  }
  /**
   * 写入,回调进度接口
   * @param sink Sink
   * @return Sink
   */
  private Sink sink(Sink sink) {
    return new ForwardingSink(sink) {
      //当前写入字节数
      long writtenBytesCount = 0L;
      //总字节长度,避免多次调用contentLength()方法
      long totalBytesCount = 0L;
      @Override
      public void write(Buffer source, long byteCount) throws IOException {
        super.write(source, byteCount);
        //增加当前写入的字节数
        writtenBytesCount += byteCount;
        //获得contentLength的值,后续不再调用
        if (totalBytesCount == 0) {
          totalBytesCount = contentLength();
        }
        Observable.just(writtenBytesCount).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() {
          @Override
          public void call(Long aLong) {
            progressListener.onProgress(writtenBytesCount, totalBytesCount);
          }
        });
      }
    };
  }
}

3自定义接口,回调progress进度

public interface UploadProgressListener {
  /**
   * 上传进度
   * @param currentBytesCount
   * @param totalBytesCount
   */
  void onProgress(long currentBytesCount, long totalBytesCount);
}

4创建RequestBody对象,加入进度

 File file=new File("/storage/emulated/0/Download/11.jpg");
   RequestBody requestBody=RequestBody.create(MediaType.parse("image/jpeg"),file);
   MultipartBody.Part part= MultipartBody.Part.createFormData("file_name", file.getName(), new ProgressRequestBody(requestBody,
       new UploadProgressListener() {
     @Override
     public void onProgress(long currentBytesCount, long totalBytesCount) {
       tvMsg.setText("提示:上传中");
       progressBar.setMax((int) totalBytesCount);
       progressBar.setProgress((int) currentBytesCount);
     }
   }));

5.传递附带信息

和封装二中post请求的方式一样,我们需要继承baseentity,复写里面的方法,然后设置需要传递的参数,因为是测试接口,所以我的参数直接写死在entity里面,part文件动态指定

/**
 * 上传请求api
 * Created by WZG on 2016/10/20.
 */

public class UplaodApi extends BaseEntity {
  /*需要上传的文件*/
  private MultipartBody.Part part;


  public UplaodApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
    super(listener, rxAppCompatActivity);
    setShowProgress(true);
  }

  public MultipartBody.Part getPart() {
    return part;
  }

  public void setPart(MultipartBody.Part part) {
    this.part = part;
  }

  @Override
  public Observable getObservable(HttpService methods) {
    RequestBody uid= RequestBody.create(MediaType.parse("text/plain"), "4811420");
    RequestBody key = RequestBody.create(MediaType.parse("text/plain"), "21f8d9bcc50c6ac1ae1020ce12f5f5a7");
    return methods.uploadImage(uid,key,getPart());
  }
}

6.post请求处理

请求和封装二中的请求一样,通过传递一个指定的HttpOnNextListener 对象来回调来监听结果信息,一一对应

 private void uploadeDo(){
   File file=new File("/storage/emulated/0/Download/11.jpg");
   RequestBody requestBody=RequestBody.create(MediaType.parse("image/jpeg"),file);
   MultipartBody.Part part= MultipartBody.Part.createFormData("file_name", file.getName(), new ProgressRequestBody(requestBody,
       new UploadProgressListener() {
     @Override
     public void onProgress(long currentBytesCount, long totalBytesCount) {
       tvMsg.setText("提示:上传中");
       progressBar.setMax((int) totalBytesCount);
       progressBar.setProgress((int) currentBytesCount);
     }
   }));
   UplaodApi uplaodApi = new UplaodApi(httpOnNextListener,this);
   uplaodApi.setPart(part);
   HttpManager manager = HttpManager.getInstance();
   manager.doHttpDeal(uplaodApi);
 }


  /**
   * 上传回调
   */
  HttpOnNextListener httpOnNextListener=new HttpOnNextListener() {
    @Override
    public void onNext(UploadResulte o) {
      tvMsg.setText("成功");
      Glide.with(MainActivity.this).load(o.getHeadImgUrl()).skipMemoryCache(true).into(img);
    }

    @Override
    public void onError(Throwable e) {
      super.onError(e);
      tvMsg.setText("失败:"+e.toString());
    }

  };

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 在项目部署后,Node.js 进程可能会遇到不可预见的错误并崩溃。为了及时通知开发人员进行问题排查,我们可以利用 nodemailer 插件来发送邮件提醒。本文将详细介绍如何配置和使用 nodemailer 实现这一功能。 ... [详细]
  • 解决Anaconda安装TensorFlow时遇到的TensorBoard版本问题
    本文介绍了在使用Anaconda安装TensorFlow时遇到的“Could not find a version that satisfies the requirement tensorboard”错误,并提供详细的解决方案,包括创建虚拟环境和配置PyCharm项目。 ... [详细]
  • 获取Jedis和Commons Pool JAR包的两种方法及详细步骤
    本文介绍如何通过网盘链接或官方网站获取Jedis和Commons Pool的JAR包,并提供详细的图文教程。同时,还附有导入JAR包到项目的相关建议。 ... [详细]
  • 本文探讨了从传统SSM(Spring + Spring MVC + MyBatis)架构到现代化Spring Boot框架的转变过程,详细分析了两者之间的差异和改进。文章结合图表展示了技术演进的关键节点,帮助读者更好地理解这一重要变革。 ... [详细]
  • 比较源文件与备份目录的差异
    本文介绍了如何有效对比源文件和备份目录之间的差异,确保数据完整性和一致性。文章提供了详细的步骤和工具推荐,帮助用户快速识别并解决潜在问题。 ... [详细]
  • 磁盘健康检查与维护
    在计算机系统运行过程中,硬件或电源故障可能会导致文件系统出现异常。为确保数据完整性和系统稳定性,定期进行磁盘健康检查至关重要。本文将详细介绍如何使用fsck和badblocks工具来检测和修复文件系统及硬盘扇区的潜在问题。 ... [详细]
  • 在跨浏览器开发中,一个常见的问题是关于如何在鼠标悬停时显示图片提示信息。本文深入探讨了 IE 浏览器对 IMG 元素 alt 属性的特殊处理,并提供了最佳实践建议。 ... [详细]
  • 本文介绍如何使用 Python 的 Pandas 库中 Series 对象的 round() 方法,对数值进行四舍五入处理。该方法在数据预处理和分析中非常有用。 ... [详细]
  • CentOS 6.5 上安装 MySQL 5.7.23 的详细步骤
    本文详细介绍如何在 CentOS 6.5 系统上成功安装 MySQL 5.7.23,包括卸载旧版本、下载安装包、配置文件修改及启动服务等关键步骤。 ... [详细]
  • DCG 创始人兼首席执行官 Barry Silbert 发布致股东信,详细解答了 19 个核心问题,并分享了公司未来的发展方向。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • Python处理Word文档的高效技巧
    本文详细介绍了如何使用Python处理Word文档,涵盖从基础操作到高级功能的各种技巧。我们将探讨如何生成文档、定义样式、提取表格数据以及处理超链接和图片等内容。 ... [详细]
  • 基于JQuery实现的评分插件
    本文介绍了一个使用JQuery创建的交互式评分控件。当用户将鼠标悬停在星星上时,左侧的星星会变为实心,右侧保持空心,并显示对应的评分等级;移开鼠标后,所有星星恢复为空心状态。 ... [详细]
  • 本文介绍了如何利用 Spring Boot 和 Groovy 构建一个灵活且可扩展的动态计算引擎,以满足钱包应用中类似余额宝功能的推广需求。我们将探讨不同的设计方案,并最终选择最适合的技术栈来实现这一目标。 ... [详细]
  • 本文介绍如何利用 Python 中的 NumPy 和 Matplotlib 库,从 NumPy 数组中绘制线图。通过具体的代码示例和详细解释,帮助读者理解并掌握这一技能。 ... [详细]
author-avatar
永恒多一天_313
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有