// 拦截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)
![](https://img-blog.csdnimg.cn/img_convert/c3a03c7efe4312074c2a1da3fd7de8df.jpeg)
最后
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。希望能够帮助到大家提升技术
高级UI,自定义View
UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。
不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
外链图片转存中…(img-IsiWz0wz-1713407172034)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/c3a03c7efe4312074c2a1da3fd7de8df.jpeg)
最后
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。希望能够帮助到大家提升技术
[外链图片转存中…(img-EqZhfM7L-1713407172035)]
高级UI,自定义View
UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。
不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!
[外链图片转存中…(img-Yo2ormWa-1713407172036)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!