// 拦截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开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!