Android带进度反馈的上传实现

<span style="font-size:14px;">算起来最近的项目应用情形,在文件上传的时候,应用HttpClient上传文件,我们总是在上传完成前使用一个进度条(一直转圈似的)来显示用户等待的过程,对于用户体验度来说这是相当不好的,大多数情况我们需要有一个详细的进度展示给用户,让用户可以知道实际的进度。刚好下发的任务要求这次项目版本升级需要加入这个功能,结合<a target=_blank href="http://toolongdidntread.com/android/android-multipart-post-with-progress-bar/" style="box-sizing: border-box; border: 0px; font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; color: rgb(210, 83, 73); text-decoration: none; -webkit-transition: all 0.3s ease-in-out; line-height: 28.78333282470703px; background-color: rgb(233, 231, 227); ">http://toolongdidntread.com/android/android-multipart-post-with-progress-bar/</a>我将其修改,作为独立的jar文件(因为依赖异步任务类,所以该jar文件只能应用于android,如果需要用于普通java应用,需要将源码中的异步任务改为开启新线程)取出来,同时提供两个回调接口:进度、服务器返回消息;</span>

package com.ilovn.libs.fileupload;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;

import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;

public class CustomMultiPartEntity extends MultipartEntity {
private final ProgressListener listener;

public CustomMultiPartEntity(final ProgressListener listener) {
super();
this.listener = listener;
}

public CustomMultiPartEntity(final HttpMultipartMode mode,
final ProgressListener listener) {
super(mode);
this.listener = listener;
}

public CustomMultiPartEntity(HttpMultipartMode mode, final String boundary,
final Charset charset, final ProgressListener listener) {
super(mode, boundary, charset);
this.listener = listener;
}

@Override
public void writeTo(final OutputStream outstream) throws IOException {
super.writeTo(new CountingOutputStream(outstream, this.listener));
}

public static interface ProgressListener {
void transferred(long num);
}

public static class CountingOutputStream extends FilterOutputStream {

private final ProgressListener listener;
private long transferred;

public CountingOutputStream(final OutputStream out,
final ProgressListener listener) {
super(out);
this.listener = listener;
this.transferred = 0;
}

public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
this.transferred += len;
this.listener.transferred(this.transferred);
}

public void write(int b) throws IOException {
out.write(b);
this.transferred++;
this.listener.transferred(this.transferred);
}
}

}

package com.ilovn.libs.fileupload;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.FormBodyPart;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import android.os.AsyncTask;
import android.util.Log;
import android.webkit.URLUtil;

import com.ilovn.libs.fileupload.CustomMultiPartEntity.ProgressListener;

/**
* 文件上传
*
* @author zhaoyong
*
*/
public class HttpMultipartPost extends AsyncTask<HttpResponse, Integer, String> {
private static final String TAG = HttpMultipartPost.class.getSimpleName();
private String url;
private long totalSize;
private String[] files;
private FormBodyPart[] parts;
private CallBack mCallBack;
private CallBackMsg mCallBackMsg;
private String encode = HTTP.UTF_8;

/**
*
* @param url
* @param files
* 文件路径
* @param parts
* 其他参数
* @param fileEncode 编码 默认UTF-8
*
*/
public HttpMultipartPost(String url, String[] files, String fileEncode,
FormBodyPart... parts) {
super();
this.url = url;
this.files = files;
this.parts = parts;
this.encode = StringUtils.isEmpty(fileEncode) ? HTTP.UTF_8 : fileEncode;
}

@Override
protected void onPreExecute() {
if (!URLUtil.isNetworkUrl(url)) {
throw new IllegalArgumentException("unvalid url for post!");
}
}

@Override
protected String doInBackground(HttpResponse... arg0) {
HttpClient httpClient = new DefaultHttpClient();
HttpContext httpContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);

try {
CustomMultiPartEntity multipartContent = new CustomMultiPartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE, null,
Charset.forName(encode), new ProgressListener() {
@Override
public void transferred(long num) {
publishProgress((int) ((num / (float) totalSize) * 100));
}
});
// add all file
for (String file : files) {
multipartContent.addPart("files", new FileBody(new File(file)));
}
// add other parts
for (FormBodyPart part : parts) {
multipartContent.addPart(part);
}
totalSize = multipartContent.getContentLength();

// Send it
httpPost.setEntity(multipartContent);
HttpResponse response = httpClient.execute(httpPost, httpContext);
String serverResponse = EntityUtils.toString(response.getEntity());
return serverResponse;
} catch (IOException e) {
return "{\"msg\":\"post failed!\"}";
}
}

@Override
protected void onProgressUpdate(Integer... progress) {
if (mCallBack != null) {
mCallBack.update(progress[0]);
}
}

@Override
protected void onPostExecute(String param) {
Log.d(TAG, param + "");
if (mCallBackMsg != null) {
mCallBackMsg.msg(param);
}
}

public void setCallBack(CallBack mCallBack) {
this.mCallBack = mCallBack;
}

public void setCallBackMsg(CallBackMsg mCallBackMsg) {
this.mCallBackMsg = mCallBackMsg;
}

public interface CallBack {
public void update(Integer i);
}

public interface CallBackMsg {
public void msg(String msg);
}
}

DEMO效果图: DEMO效果图
转自:http://www.ilovn.com/topic/upload-android-with-feedback-on-the-progress-of-implementation/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Android 中使用 OkHttp 实现进度的文件上,可以使用 OkHttp 提供的 Interceptor 和 RequestBody 类。下面是一个简单的示例代码: ```java public class ProgressRequestBody extends RequestBody { private static final int DEFAULT_BUFFER_SIZE = 2048; private final File file; private final String contentType; private final ProgressListener listener; public ProgressRequestBody(File file, String contentType, ProgressListener listener) { this.file = file; this.contentType = contentType; this.listener = listener; } @Override public MediaType contentType() { return MediaType.parse(contentType); } @Override public long contentLength() { return file.length(); } @Override public void writeTo(BufferedSink sink) throws IOException { long fileLength = file.length(); byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; long uploaded = 0; try (InputStream in = new FileInputStream(file)) { int read; while ((read = in.read(buffer)) != -1) { uploaded += read; sink.write(buffer, 0, read); if (listener != null) { listener.onProgress(uploaded, fileLength); } } } } public interface ProgressListener { void onProgress(long uploaded, long total); } } ``` 这个类继承自 OkHttp 的 RequestBody 类,并实现了上文件进度监听。在 writeTo() 方法中使用 InputStream 从文件中读取数据,并将数据写入 BufferedSink 中。同时,每次写入数据都会调用 onProgress() 方法通知进度监听器。 然后,创建一个 OkHttpClient,添加一个 Interceptor,该 Interceptor 使用 ProgressRequestBody 替换 RequestBody,从而实现进度监听: ```java OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request original = chain.request(); // 使用 ProgressRequestBody 替换 RequestBody ProgressRequestBody requestBody = new ProgressRequestBody(file, contentType, listener); Request request = original.newBuilder() .method(original.method(), requestBody) .build(); return chain.proceed(request); } }) .build(); ``` 其中,file 是要上的文件,contentType 是文件的 MIME 类型,listener 是进度监听器。最后,使用 OkHttpClient 发起一个上文件的 Request: ```java Request request = new Request.Builder() .url(uploadUrl) .post(requestBody) .build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 上失败 } @Override public void onResponse(Call call, Response response) throws IOException { // 上成功 } }); ``` 在 onResponse() 方法中处理上结果即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值