Retrofit2 & RxJava2实现单文件和多文件上传

// 拦截okHttp的日志,如果开启了会导致上传回调被调用两次

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();

interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

builder.addInterceptor(interceptor);

}

// 超时时间

builder.connectTimeout(15, TimeUnit.SECONDS);// 15S连接超时

builder.readTimeout(20, TimeUnit.SECONDS);// 20s读取超时

builder.writeTimeout(20, TimeUnit.SECONDS);// 20s写入超时

// 错误重连

builder.retryOnConnectionFailure(true);

okHttpClient = builder.build();

}

}

}

return okHttpClient;

}

}

这个类主要是获取OkHttpClient示例,设置它的一些参数,比如超时时间,拦截器等等.

封装RetrofitClient类


/**

  • RetrofitClient.

  • @author devilwwj

  • @since 2017/7/12

*/

public class RetrofitClient {

private static RetrofitClient mInstance;

private static Retrofit retrofit;

private RetrofitClient() {

retrofit = RetrofitBuilder.buildRetrofit();

}

/**

  • 获取RetrofitClient实例.

  • @return 返回RetrofitClient单例

*/

public static synchronized RetrofitClient getInstance() {

if (mInstance == null) {

mInstance = new RetrofitClient();

}

return mInstance;

}

private T create(Class clz) {

return retrofit.create(clz);

}

/**

  • 单上传文件的封装.

  • @param url 完整的接口地址

  • @param file 需要上传的文件

  • @param fileUploadObserver 上传回调

*/

public void upLoadFile(String url, File file,

FileUploadObserver fileUploadObserver) {

UploadFileRequestBody uploadFileRequestBody =

new UploadFileRequestBody(file, fileUploadObserver);

create(UploadFileApi.class)

.uploadFile(url, MultipartBuilder.fileToMultipartBody(file,

uploadFileRequestBody))

.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

.subscribe(fileUploadObserver);

}

/**

  • 多文件上传.

  • @param url 上传接口地址

  • @param files 文件列表

  • @param fileUploadObserver 文件上传回调

*/

public void upLoadFiles(String url, List files,

FileUploadObserver fileUploadObserver) {

create(UploadFileApi.class)

.uploadFile(url, MultipartBuilder.filesToMultipartBody(files,

fileUploadObserver))

.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

.subscribe(fileUploadObserver);

}

}

这个是Retrofit客户端类,获取它的单例然后去调用它的上传文件的方法,可以看到我这里封装了两个方法,uploadFile是上传单个文件,uploadFiles方法上传多个文件.

因为我们需要构造一个Retrofit对象,所以这里有一个RetrofitBuilder类:

/**

  • Retrofit构造器.

  • @author devilwwj

  • @since 2017/7/13

*/

public class RetrofitBuilder {

private static Retrofit retrofit;

public static synchronized Retrofit buildRetrofit() {

if (retrofit == null) {

Gson gson = new GsonBuilder().setDateFormat(“yyyy-MM-dd HH:mm:ss”).create();

GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create(gson);

retrofit = new Retrofit.Builder().client(OkHttpManager.getInstance())

.baseUrl(AppConfig.HTTP_SERVER)

.addConverterFactory(gsonConverterFactory)

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

.build();

}

return retrofit;

}

}

可以看到,想构造Retrofit对象是需要获取OkhttpClient实例的。

定义上传文件接口


/**

  • 上传API.

  • @author devilwwj

  • @since 2017/7/12

*/

public interface UploadFileApi {

String UPLOAD_FILE_URL = AppConfig.HTTP_SERVER + “file/upload”;

@POST

Observable uploadFile(@Url String url, @Body MultipartBody body);

}

这里就是Retrofit定义接口的形式,通过注解来表示各个参数,@POST表示发起post请求,@Url表示这是个请求地址,@Body表示这是请求体,关于Retrofit的各种注解的使用这里不多说,大家可以自行了解。

构造MultipartBody


上一步定义好了上传的接口,我们最终是要去构造MultipartBody,这一块就需要跟后台同学进行沟通了,根据接口定义来实现,这里是我们的实现:

/**

  • MultipartBuilder.

  • @author devilwwj

  • @since 2017/7/13

*/

public class MultipartBuilder {

/**

  • 单文件上传构造.

  • @param file 文件

  • @param requestBody 请求体

  • @return MultipartBody

*/

public static MultipartBody fileToMultipartBody(File file, RequestBody requestBody) {

MultipartBody.Builder builder = new MultipartBody.Builder();

JsonObject jsonObject = new JsonObject();

jsonObject.addProperty(“fileName”, file.getName());

jsonObject.addProperty(“fileSha”, Utils.getFileSha1(file));

jsonObject.addProperty(“appId”, “test0002”);

builder.addFormDataPart(“file”, file.getName(), requestBody);

builder.addFormDataPart(“params”, jsonObject.toString());

builder.setType(MultipartBody.FORM);

return builder.build();

}

/**

  • 多文件上传构造.

  • @param files 文件列表

  • @param fileUploadObserver 文件上传回调

  • @return MultipartBody

*/

public static MultipartBody filesToMultipartBody(List files,

FileUploadObserver fileUploadObserver) {

MultipartBody.Builder builder = new MultipartBody.Builder();

JsonArray jsonArray = new JsonArray();

Gson gson = new Gson();

for (File file : files) {

UploadFileRequestBody uploadFileRequestBody =

new UploadFileRequestBody(file, fileUploadObserver);

JsonObject jsonObject = new JsonObject();

jsonObject.addProperty(“fileName”, file.getName());

jsonObject.addProperty(“fileSha”, Utils.getFileSha1(file));

jsonObject.addProperty(“appId”, “test0002”);

jsonArray.add(jsonObject);

LogUtil.d(jsonObject.toString());

builder.addFormDataPart(“file”, file.getName(), uploadFileRequestBody);

}

builder.addFormDataPart(“params”, gson.toJson(jsonArray));

LogUtil.d(gson.toJson(jsonArray));

builder.setType(MultipartBody.FORM);

return builder.build();

}

}

自定义RequestBody


构造MultipartBody是需要去创建每个文件对应的ReqeustBody,但我们这边需要监听到文件上传成功、失败和进度的状态,所以需要去自定义:

/**

  • 上传文件请求body.

  • @author devilwwj

  • @since 2017/7/12

*/

public class UploadFileRequestBody extends RequestBody {

private RequestBody mRequestBody;

private FileUploadObserver fileUploadObserver;

public UploadFileRequestBody(File file, FileUploadObserver fileUploadObserver) {

this.mRequestBody = RequestBody.create(MediaType.parse(“application/octet-stream”), file);

this.fileUploadObserver = fileUploadObserver;

}

@Override

public MediaType contentType() {

return mRequestBody.contentType();

}

@Override

public long contentLength() throws IOException {

return mRequestBody.contentLength();

}

@Override

public void writeTo(BufferedSink sink) throws IOException {

CountingSink countingSink = new CountingSink(sink);

BufferedSink bufferedSink = Okio.buffer(countingSink);

// 写入

mRequestBody.writeTo(bufferedSink);

// 刷新

// 必须调用flush,否则最后一部分数据可能不会被写入

bufferedSink.flush();

}

/**

  • CountingSink.

*/

protected final class CountingSink extends ForwardingSink {

private long bytesWritten = 0;

public CountingSink(Sink delegate) {

super(delegate);

}

@Override

public void write(Buffer source, long byteCount) throws IOException {

super.write(source, byteCount);

bytesWritten += byteCount;

if (fileUploadObserver != null) {

fileUploadObserver.onProgressChange(bytesWritten, contentLength());

}

}

}

}

这里有个RxJava2的Observer的抽象类,主要是用来收到Rxjava2的事件:

/**

  • 上传文件的RxJava2回调.

  • @author devilwwj

  • @since 2017/7/12

  • @param 模板类

*/

public abstract class FileUploadObserver extends DefaultObserver {

@Override

public void onNext(T t) {

onUploadSuccess(t);

}

@Override

public void onError(Throwable e) {

onUploadFail(e);

}

@Override

public void onComplete() {

}

// 上传成功的回调

public abstract void onUploadSuccess(T t);

// 上传失败回调

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-cb9hoNZ9-1715763629835)]

[外链图片转存中…(img-4wfV82z5-1715763629837)]

[外链图片转存中…(img-XUN0ok4p-1715763629838)]

[外链图片转存中…(img-A0GgGQLy-1715763629839)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值