背景
在实际运用中上传是一个必不可少的功能,所以我们在封装二的基础上加入上传的功能,同时需要附带上传进度!
效果
实现
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()); } };