冲天香阵透长安,满城尽带黄金甲。这篇文章主要讲述Android开发 retrofit下载与上传相关的知识,希望能为你提供帮助。
前言
此博客只讲解retrofit下载与上传的使用,其实与其说是retrofit的下载与上传还不如说,依然是Okhttp的下载与上传.如果你需要了解retrofit入门请查看这篇博客(此博客不在详细讲解一些基础的东西):https://www.cnblogs.com/guanxinjing/p/11594249.html
下载
设置下载接口
public interface HttpList {@Streaming //注解这个请求将获取数据流,此后将不会这些获取的请求数据保存到内存中,将交与你操作. @GET Call< ResponseBody> download(@Url String url); }
这里有一个很重要的东西! @Url属性, 这个属性是你导入的下载地址. 它可以是绝对地址和可以是相对地址,当你使用这个属性的时候,Retrofit设置基础Url的baseUrl("http://p.gdown.baidu.com/") 将自动判断地址是绝对还是相对,从而选择拼接Url还是替换Url !
请求下载
private void downloadFile() { final File file = new File(getExternalCacheDir(), "demo.apk"); if (file.exists()) { file.delete(); }Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://p.gdown.baidu.com/")//base的网络地址 .callbackExecutor(Executors.newSingleThreadExecutor())//设置线程,如果不设置下载在读取流的时候就会报错 .build(); HttpList httpList = retrofit.create(HttpList.class); Call< ResponseBody> call = httpList.download(DOWNLOAD_URL_PATH); //下载地址太长了所以我用DOWNLOAD_URL_PATH封装了一下,不要误解call.enqueue(new Callback< ResponseBody> () { @Override public void onResponse(Call< ResponseBody> call, Response< ResponseBody> response) { try { long total = response.body().contentLength(); //需要下载的总大小 long current = 0; InputStream inputStream = response.body().byteStream(); FileOutputStream fileOutputStream = new FileOutputStream(file); byte[] bytes = new byte[1024]; int len = 0; while ((len = inputStream.read(bytes)) != -1) { fileOutputStream.write(bytes, 0, len);
fileOutputStream.flush(); current = current + len; Log.e(TAG, "已经下载=" + current + " 需要下载=" + total); } fileOutputStream.flush(); fileOutputStream.close(); inputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }@Override public void onFailure(Call< ResponseBody> call, Throwable t) {} }); }
以上的下载实现的关键点,其实是ResponseBody,而这个其实就是okhttp的请求接口后返回的响应body. Retrofit并没有对这个进行封装,所以如果你了解okhttp的使用,应该是轻轻松松的.
【Android开发 retrofit下载与上传】
上传 上传一般有好几种情况:
- 不需要进度的上传
- 需要进度的上传
- 批量上传
public interface HttpList { @Multipart @POST("test/upfile") Call< ResponseBody> upFile(@Part MultipartBody.Part part); }
注意这里的Body是 MultipartBody
上传实现
/** * 无进度上传 */ private void updateFile(){ final File imageFile = new File(getExternalCacheDir() + "/image/demo.jpg"); if (!imageFile.getParentFile().exists()){ imageFile.getParentFile().mkdirs(); }Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://www.doclever.cn:8090/mock/5ba0c147fa08107daa8c55c2/") .callbackExecutor(Executors.newSingleThreadExecutor()) .build(); HttpList list = retrofit.create(HttpList.class); // /* * "image/jpg" 是你要上传的文件的格式 这个格式并不是固定的,是根据你的项目使用那些何种key也有很多是使用下面这个: *RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), imageFile); */ RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpg"), imageFile); //注意这里的file是对应MultipartBody上传文件的key名称 MultipartBody.Part multipartBody = MultipartBody.Part.createFormData("file", imageFile.getName(), requestFile); Call< ResponseBody> call = list.upFile(multipartBody); call.enqueue(new Callback< ResponseBody> () { @Override public void onResponse(Call< ResponseBody> call, Response< ResponseBody> response) { try { Log.e(TAG, "onResponse: 上传成功 "+response.body().string()); } catch (IOException e) { e.printStackTrace(); }}@Override public void onFailure(Call< ResponseBody> call, Throwable t) {} }); }
有进度的文件上传
/** * 有进度的上传 */ private void updateFile(){ final File imageFile = new File(getExternalCacheDir() + "/image/demo.jpg"); if (!imageFile.getParentFile().exists()){ imageFile.getParentFile().mkdirs(); }Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://www.doclever.cn:8090/mock/5ba0c147fa08107daa8c55c2/") .callbackExecutor(Executors.newSingleThreadExecutor()) .build(); HttpList list = retrofit.create(HttpList.class);
RequestBody requestFile = new RequestBody() { @Nullable @Override public MediaType contentType() { return MediaType.parse("image/jpg"); //这里返回上传的格式 根据项目情况也可以切换成"multipart/form-data" 等等其他格式 }@Override public void writeTo(BufferedSink sink) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile(imageFile, "rw"); long totalLength = 0; long currentUpLength = 0; if (totalLength == 0) { totalLength = randomAccessFile.length(); } byte[] bytes = new byte[2048]; int len = 0; try { while ((len = randomAccessFile.read(bytes)) != -1) { sink.write(bytes, 0, len); currentUpLength = currentUpLength + len; Log.e(TAG, "writeTo: totalLength="+totalLength + " currentUpLength="+currentUpLength); } }catch (Exception e){ Log.e(TAG, "上传中断"); }finally { randomAccessFile.close(); //关闭流 Log.e(TAG, "流关闭"); }} }; MultipartBody.Part multipartBody = MultipartBody.Part.createFormData("file", imageFile.getName(), requestFile); Call< ResponseBody> call = list.upFile(multipartBody); call.enqueue(new Callback< ResponseBody> () { @Override public void onResponse(Call< ResponseBody> call, Response< ResponseBody> response) { try { Log.e(TAG, "onResponse: 上传成功 "+response.body().string()); } catch (IOException e) { e.printStackTrace(); }}@Override public void onFailure(Call< ResponseBody> call, Throwable t) {} }); }
批量上传文件(无对应key的批量上传) 接口服务类
public interface HttpList { @Multipart @POST("test/upfileList") Call< ResponseBody> upFileList(@Part List< MultipartBody.Part> partList); }
其他与单个上传一致
批量上传文件(有对应key的批量上传) 接口服务类
public interface HttpList { @Multipart @POST("test/upfileList") Call< ResponseBody> upFileList(@PartMap Map< String, RequestBody> map); }
实现批量上传
private void updateFile3(){ final File imageFile1 = new File(getExternalCacheDir() + "/image/demo_1.jpg"); final File imageFile2 = new File(getExternalCacheDir() + "/image/demo_2.jpg"); final File imageFile3 = new File(getExternalCacheDir() + "/image/demo_3.jpg"); RequestBody requestFile1 = RequestBody.create(MediaType.parse("multipart/form-data"), imageFile1); RequestBody requestFile2 = RequestBody.create(MediaType.parse("multipart/form-data"), imageFile2); RequestBody requestFile3 = RequestBody.create(MediaType.parse("multipart/form-data"), imageFile3); Map< String, RequestBody> map = new HashMap< > (); map.put("file1", requestFile1); //file1 就是需要上传每个文件的key名称 map.put("file2", requestFile2); map.put("file3", requestFile3); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://www.doclever.cn:8090/mock/5ba0c147fa08107daa8c55c2/") .callbackExecutor(Executors.newSingleThreadExecutor()) .build(); HttpList list = retrofit.create(HttpList.class); Call< ResponseBody> call = list.upFileList(map); call.enqueue(new Callback< ResponseBody> () { @Override public void onResponse(Call< ResponseBody> call, Response< ResponseBody> response) { //上传成功}@Override public void onFailure(Call< ResponseBody> call, Throwable t) {} }); }
end
推荐阅读
- Android自动化测试------monkeyrunner
- 论文研读《Deep Learning and Its Applications to MachineHealth Monitoring: A Survey》
- android couldn't find so
- 安卓直连SQLSEVER数据库
- 通过AS提交AndroidLibrary到JCenter仓库
- Expected a key while parsing a block mapping.
- appium 多线程还是多进程(转)
- 解决AndroidKiller APK 反编译失败,无法继续下一步源码反编译!
- httpclient模拟post(applecation/x-www-form-urlencoded方式)请求