本文主要是介绍retrofit2+okhttp3图片上传及进度监听,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、使用jar包
由于retrofit2与1的写法有很大的变化,并且对okhttp存在着依赖。所以需要确定选择使用方向,以免陷入不必要的坑中。
本篇讲采用retrofit2 + okhttp3做结合使用。在导包过程中本人也遇到了一些不兼容的麻烦,再此做记录。
retrofit-2.1.0.jar、okhttp-3.4.1.jar、okio-1.6.0.jar、converter-gson-2.1.0.jar
另外我们服务端使用springmvc框架,通过@responseBody返回。前期引入gson包为gson-2.4.jar总报错不知何故,最后换成gson-2.7.jar就可以了。
2、使用retrofit
retrofit使用是有一定规律性,我们可以将其归纳后提出,封装一个针对retrofit的制造者。
public class RetrofitBuilder{private static Retrofit retrofit;public synchronized static Retrofit buildRetrofit(String url){if(retrofit == null){OkHttpClient client = new OkHttpClient.Builder().retryOnConnectionFailure(true).build();retrofit = new Retrofit.Builder.client(client).baseUrl(url).addConverterFactory((GsonConverterFactory.create())).build();}return retrofit;}
}
retrofit对应请求接口
public interface FileuploadService{/***@param parts*@param map(请求参数)*@return(JsonRetrun实体类)*/@Multipart@POST("uploader")Call<JsonReturn> uploadFilesWithParts(@Part() List<MultipartBody.Part> parts , @QueryMap Map<String , String> map);/***@param body*@param map(请求参数)*@return(JsonRetrun实体类)*/@Multipart@POST("uploader")Call<JsonReturn> uploadFilesWithBody(@Body() MultipartBody body , @QueryMap Map<String , String> map);
}
回执泛型实体类
public class JsonReturn{private String errcode;private String errmsg;private String msg;private Object object;set/get方法.....
}
接口中Multipart参数生成,可以封装一个创造者。
public class MultipartBuiler{public static MultipartBody filesToBody(List<File> files , RetrofitCallback<JsonReturn> callback){for(File file : files){RequestBody requestBody = RequestBody.create(MediaType.parse("img/png"),file);FileRequestBody body = new FileRequestBody(reqeustBody , callback , file);builder.addFormDataPart("file" , file.getName , body);}builder.setType(MultipartBody.FORM);MultipartBody multipartBody = builder.build();return multipartBody;}public staitc List<MultipartBody.Part> filesToParts(List<File> files , RetrofitCallback<JsonReturn> callback){List<MultipartBody.Part> parts = new ArrayList<>(files.size());for(File file : files){RequestBody requestBody = RequestBody.create(MediaType.parse("img/png"),file);FileRequestBody body = new FileRequestBody(reqeustBody , callback , file);MultipartBody.Part part = MultipartBody.Part.createFormData("file" , file.getName() , body);parts.add(part);}return parts;}
}
以上可以实现文件的上传了。
3、有的时候我们在项目中需要监听文件的上传进度,那要如何实现呢。继续往下看思路。
上传的过程,我们可以考虑为request的交互过程,所以我们完全可以针对okhttp中的requestBody做些扩展。
/*** 扩展Okhttp的请求体, 实现上传时的进度监听* @author xuximing** @param <T>*/
public class FileRequestBody<T> extends RequestBody {/*** 实体请求体*/private RequestBody requestBody;/*** 上传回调接口*/private RetrofitCallback<T> callback;/*** 文件*/private File file ;/*** 包装完成的BufferedSink*/private BufferedSink bufferedSink;public FileRequestBody(RequestBody requestBody , RetrofitCallback<T> callback , File file){super();this.requestBody = requestBody;this.callback = callback;this.file = file;}@Overridepublic long contentLength() throws IOException {return requestBody.contentLength();}@Overridepublic MediaType contentType() {return requestBody.contentType();}@Overridepublic void writeTo(BufferedSink sink) throws IOException {if(bufferedSink == null){//包装bufferedSink = Okio.buffer(sink(sink));}//写入requestBody.writeTo(bufferedSink);//必须调用flush,否则最后一部分数据可能不会被写入bufferedSink.flush();}/*** 写入,回调进度接口* @param sink* @return*/private Sink sink(Sink sink){return new ForwardingSink(sink) {//当前写入字节数long bytesWritten = 0L;//总字节长度,避免多次调用contentLength()方法long contentLength = 0L;@Overridepublic void write(Buffer source, long byteCount) throws IOException {super.write(source, byteCount);if(contentLength == 0){//获得contentLength的值,后续不再调用contentLength = contentLength();}//增加当前写入的字节数bytesWritten += byteCount;//回调callback.onLoading(file , contentLength, bytesWritten);}};}
}
retrofit中callback不能完全满足我们的需求,我们也可以进一步扩展
public abstract class RetrofitCallback<T> implements Callback<T>{@Overridepublic void onResponse(Call<T> call, Response<T> response) {if(response.isSuccessful()){onSuccess(call, response);}else{onFailure(call, new Throwable(response.message()));}}public abstract void onSuccess(Call<T> call , Response<T> response);public void onLoading(File file , long total , long progress){}
}
4、最终使用
使用起来用到的代码依旧相同,那我们在次提取封装
public class UploadFileUitl{public UploadFileUitl(String url , Map<> paramMap , List mList , RetrofitCallBack callback){List<MultipartBody.Part> parts = MultipartBuilder.filesToParts(mList , callback);//创建Multipart//创建Retrofit,并调用enqueue实现异步操作RetrofitBuilder.buildRetrofit(url).create(FileUploadService.class)'.uploadFilesWithParts(parts , paramMap).enqueue(callback);}
}
ok,开始最终的调用吧
new UploadFileUtil(url , paramMap , fileList , new RetrofitCallback(){//成功@Overridepublic void onSuccess(Call call , Response response){}//失败@Overridepublic void onFailure(Call call , Throwable t){}//加载中@Overridepublic void onLoading(File file , long total , long progress){}
});
不要忘记android的规则,对一些耗时操作不要放在主线程中。因此我们还需要将最终调用放到子线程中。我用的是AsyncTask
class UploadTask extends AsyncTask<Map , Map , Object>{//在执行过程中调用上传监听过程@Overrideprotected Object doInBackground(Map... params){new UploadFileUtil(url , paramMap , fileList , new RetrofitCallback(){//成功@Overridepublic void onSuccess(Call call , Response response){}//失败@Overridepublic void onFailure(Call call , Throwable t){}//加载中@Overridepublic void onLoading(File file , long total , long progress){....publishProgress(map);//出发处理进度}});}//处理进度@Overrideprotected void onProgressUpdate(Map... maps){}
}
这篇关于retrofit2+okhttp3图片上传及进度监听的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!