安卓中带进度显示的图片上传
来源:互联网 发布:朋友圈图文制作软件 编辑:程序博客网 时间:2024/05/28 23:20
接上一篇:安卓选择图片上传功能
在这篇文章的基础上继续打造带进度的图片上传功能。过程蛮复杂,在本文中将贴出大量代码。嫌字多不看的出门左转。另外在上一篇文章中问我要demo的同学们,待后期我上传github后贴出地址。
前言
在查阅了大量资料以后,现在首先对于上传文件主要有两种方式。
- 把文件转换成字符串通过json格式上传【参考xutils3的post联网请求方式】
- 直接封装成一个File对象然后通过表单方式上传【参考okhttp上传文件方式】
首先第一种方式就是普通的联网请求,这种方式有人告诉我,如果是通过json格式去入参的话,无法拿到进度回调。因为json是拼接完成之后一次性全部发送。我不知道这种说法是否有依据来源。也就是说如果要实现进度,那么就要采用以文件形式上传,换而言之也就是流的概念。
一开始我采用的是HttpUrlConnection这种原始的联网工具,实际证明,这种方式只能拿到从堆内存中读到缓存中的进度,而不能拿到上传过程中的进度。在网上找寻许久,最后找到的方法综合起来,都是把okhttp的请求体进行封装来拿到进度。那么下面我们来看一下代码。
代码
其中最重要的文件是ProgressRequestBody
public class ProgressRequestBody extends RequestBody { private RequestBody mRequestBody;//真正的mRequestBody private OnProgressListener mProgressListener;//上传回调接口 /** * 构造函数,赋值 * * @param requestBody 待包装的请求体 * @param progressListener 回调接口 */ public ProgressRequestBody(RequestBody requestBody, OnProgressListener progressListener) { mRequestBody = requestBody; mProgressListener = progressListener; } public interface OnProgressListener { void OnProgress(long byteWrite, long contentLength); } /** * 重写调用实际的响应体的contentType * * @return MediaType */ @Override public MediaType contentType() { return mRequestBody.contentType(); } @Override public long contentLength() { try { return mRequestBody.contentLength();//总字节长度 } catch (IOException e) { return -1; } } /** * 重写进行写入 * * @param sink BufferedSink * @throws IOException 异常 */ @Override public void writeTo(BufferedSink sink) throws IOException { CountingSink countingSink = new CountingSink(sink); BufferedSink bufferedSink = Okio.buffer(countingSink); mRequestBody.writeTo(bufferedSink); bufferedSink.flush(); } protected final class CountingSink extends ForwardingSink { private long byteWrite;//当前写入字节数 public CountingSink(Sink delegate) { super(delegate); } @Override public void write(Buffer source, long byteCount) throws IOException { super.write(source, byteCount); byteWrite += byteCount; mProgressListener.OnProgress(byteWrite, contentLength()); } }
这个重写的类看起来还是挺复杂的,简单解释一下,这个类是把okhttp中的RequestBody进行了封装,并且在里面设计了一个接口,在ForwardingSink这个抽象类里把进度暴露出来,这样的解释不知道有没有明白,如果不明白我还是建议去学习接口回调,这个东西的重要性不必多说。
然后在外部再封装一层,封装一层的原因是为了后期在这里做一些其他需求的操作。
public class CountingRequestBody extends ProgressRequestBody { /** * 再封装一层 * * @param requestBody 请求体 * @param progressListener 上传进度监听 */ public CountingRequestBody(RequestBody requestBody, OnProgressListener progressListener) { super(requestBody, progressListener); }}
然后使用它
public class OkHttpUploadFileUtils { /** * 上传文件 * 注意:这里的字段不能为null不然会报空指针 * * @param file_path 文件路径 * @param po 上传实体 * @param callBack 外部回调 */ public static void uploadFile(String file_path, FilePo po, final UploadCallBack callBack) { File file = new File(file_path); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("service", "--") .addFormDataPart("bucketName", po.getBucketName()) .addFormDataPart("key", po.getKey()) .addFormDataPart("system", po.getSystem()) .addFormDataPart("file_name", po.getFile_name()) .addFormDataPart("file_size", file.length() + "") .addFormDataPart("file_type", po.getFile_type()) .addFormDataPart("operation", po.getOperation()) .addFormDataPart("operator_id", po.getOperator_id()) .addFormDataPart("operator_name", po.getOperator_name()) .addFormDataPart("appkey", "--") .addFormDataPart("language", "--") .addFormDataPart("token", TpzIniUtils.getString("token_login", null)) .addFormDataPart( "inputStream", file.getName(), RequestBody.create(MediaType.parse("application/octet-stream"), file) ) .build(); CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.OnProgressListener() { @Override public void OnProgress(long byteWrite, long contentLength) { callBack.onUploading(byteWrite * 100 / contentLength);//暴露进度 } }); Request request = new Request.Builder() .url(UrlList.PREFIX_URL) //URL .post(countingRequestBody) .build(); execute(request, callBack); } //发起请求 private static void execute(Request request, UploadCallBack callBack) { try { Call call = BaseApplication.okHttpClient.newCall(request); Response response = call.execute();//这里用的是同步回调 JsonResults<FileUploadedBean> jsonResult = JsonTools.convertFromJson( response.body().string(), new TypeToken<JsonResults<FileUploadedBean>>() { }); if (jsonResult.getResult_data().isResult()) { callBack.onSuccess(jsonResult.getResult_data().isResult(), jsonResult.getResult_data().getFile_id()); } else { callBack.onFailed(null);//失败回调 } } catch (Exception e) { callBack.onFailed(e);//失败回调 } callBack.onFinish();//结束回调 }}
这里有一些我项目中的东西不便于暴露,我想大多数中级水平的开发者都能看得懂。我自己设计了一个接口用于暴露数据,如下:
public interface UploadCallBack { void onSuccess(boolean result, String attach_id); void onFailed(Exception e); void onFinish(); void onUploading(float progress);}
这里使用的是一个同步的联网操作,如果有朋友有比较好的异步上传的逻辑欢迎留言评论。
然后在外部文件中调用:
OkHttpUploadFileUtils.uploadFile(imgList.get(i).getImg_url(), filePo, new UploadCallBack() { @Override public void onSuccess(boolean result, String attach_id) { imgList.get(finalI).setAttach_id(attach_id); setImgUploaderProgress(imgList.get(finalI), 100, result); } @Override public void onFailed(Exception e) { setImgUploaderProgress(imgList.get(finalI), 100, false); } @Override public void onFinish() { } @Override public void onUploading(float progress) { if (progress < 100) { setImgUploaderProgress(imgList.get(finalI), (int) progress, true); } } }); }
这个方法可能部分人看不明白,这是我针对自己的逻辑做的一些UI处理,在onUploading这个方法中可以看到,进度从里面暴露出来。
实际效果:
后记
我师傅不让我使用一些第三方的工具,他说不能只做个搬运工,复制粘贴。有些东西还是要知道一下原理。进行二次封装,也避免了项目中引入大量依赖。尽可能的在能力之内维持项目的精简高效。
- 安卓中带进度显示的图片上传
- Retrofit图片上传及进度的显示
- 使用AFN上传图片,显示上传进度
- 自定义View实现图片上传进度显示
- AFNetworking 3.0 上传图片 进度progress显示
- 封装AFN+图片上传进度在图片上显示
- 基于Bootstrap的多图片(文件也可以)上传、预览、删除、缩放、进度...显示
- ASIProgressDelegate:实现定制的上传进度显示
- 半圆遮挡图片 实现百分比显示上传进度
- 《Android-圆形图片处理(上传)进度显示》
- WebView加载网页-进度显示-网络上传图片并压缩
- 基于SpringMVC+Bootstrap实现图片异步上传进度显示
- PHP 显示上传进度
- fileupload上传显示进度
- 一个简单的ajax上传 上传进度显示
- android自定义View实现图片上传进度显示(仿手机QQ上传效果)
- android自定义View实现图片上传进度显示(仿手机QQ上传效果)
- android自定义View实现图片上传进度显示(仿手机QQ上传效果)
- 安卓选择图片上传功能
- 安卓开发引用ttf字体文件
- 提高SQL查询效率
- 在项目启动时就执行某些操作
- 关于Spring Cloud大型互联网分布式企业微服务云架构
- 安卓中带进度显示的图片上传
- Eclipse报错:java.lang.ClassNotFoundException: ContextLoaderListener 问题
- Androidz中DragGrid的基础使用(结合Tablyout)
- STM32的GPIO的复用功能和重映射功能
- 安卓中如何给按钮添加点击音效
- 数据库SQL性能优化(三)
- Rem值与Px之间的换算
- Visual Studio提示未找到 Git。请安装 Git,或在 "git.path" 设置中配置
- STM32的SPI学习笔记