Android OkHttp 文件上传如何获取上传进度
在Android开发中,使用OkHttp库进行文件上传是一种常见的方式。然而,当上传大文件时,我们通常希望能够获取上传进度以提供更好的用户体验。本文将介绍如何使用OkHttp来实现文件上传并获取上传进度。
实际问题
在实际开发中,我们可能需要上传用户拍摄的照片或者录制的视频等大文件。由于文件较大,上传过程可能需要一段时间。为了提供更好的用户体验,我们希望能够显示上传进度,让用户清楚地知道上传的进展情况。
解决方案
为了获取上传进度,我们需要使用OkHttp的RequestBody和Interceptor。
1. 添加依赖
首先,在项目的build.gradle文件中添加OkHttp的依赖:
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
}
2. 创建上传任务
我们可以创建一个UploadTask类来封装文件上传的逻辑。在该类中,我们需要定义一个接口来回调上传进度:
public class UploadTask {
private static final String TAG = "UploadTask";
public interface ProgressListener {
void onProgress(long bytesWritten, long contentLength, boolean done);
}
public void uploadFile(File file, ProgressListener listener) {
OkHttpClient client = new OkHttpClient().newBuilder()
.addInterceptor(new ProgressInterceptor(listener))
.build();
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("multipart/form-data"), file))
.build();
Request request = new Request.Builder()
.url("http://your-upload-url")
.post(requestBody)
.build();
try {
Response response = client.newCall(request).execute();
// 处理上传结果
} catch (IOException e) {
e.printStackTrace();
}
}
}
在uploadFile方法中,我们创建了一个OkHttpClient实例,并添加了一个Interceptor(ProgressInterceptor)来监听上传进度。然后,我们构建了一个MultipartBody,将文件添加为表单数据,并发送POST请求。
注意:在示例代码中的URL处应该替换为你自己的上传接口地址。
3. 实现进度监听器
我们需要自定义一个Interceptor来监听上传进度,并通过回调函数通知上传进度的变化。下面是ProgressInterceptor的实现:
public class ProgressInterceptor implements Interceptor {
private static final String TAG = "ProgressInterceptor";
private UploadTask.ProgressListener mListener;
public ProgressInterceptor(UploadTask.ProgressListener listener) {
mListener = listener;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Response originalResponse = chain.proceed(originalRequest);
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), mListener))
.build();
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody mResponseBody;
private final UploadTask.ProgressListener mListener;
private BufferedSource mBufferedSource;
public ProgressResponseBody(ResponseBody responseBody, UploadTask.ProgressListener listener) {
mResponseBody = responseBody;
mListener = listener;
}
@Override
public MediaType contentType() {
return mResponseBody.contentType();
}
@Override
public long contentLength() {
return mResponseBody.contentLength();
}
@Override
public BufferedSource source() {
if (mBufferedSource == null) {
mBufferedSource = Okio.buffer(source(mResponseBody.source()));
}
return mBufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
if (mListener != null) {
mListener.onProgress(totalBytesRead, mResponseBody.contentLength(), bytesRead == -1);
}
return bytesRead;
}
};
}
}
}
在ProgressInterceptor中,我们通过调用chain.proceed(originalRequest)来获取原始的Response对象。然后,我们构建一个新的Response对象,将原始的ResponseBody替换为自定义的ProgressResponseBody。ProgressResponseBody会在读取数据时回调进度监听器。
4. 使用示例
使用UploadTask来上传文件并监听上传进度的示例如下:
public class MainActivity extends AppCompatActivity {
private static final String