// 拦截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);
// 上传失败回调
写在最后
今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
【算法合集】
【延伸Android必备知识点】
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
失败回调
写在最后
今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
[外链图片转存中…(img-lt5Duzm7-1715685981364)]
【算法合集】
[外链图片转存中…(img-YlV9x1R2-1715685981366)]
【延伸Android必备知识点】
[外链图片转存中…(img-vpbWrACM-1715685981368)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!