OkHttp实现文件上传进度监听回调

本文简单写一下自己用到的OkHttp表单提交文件监听回调

本文用kotlin实现

首先有这样一个问题,文件上传进度哪里来? 因为我们是将文件上传到服务器,我们可以把文件解读成一个字节一个字节的上传,这样,我们读取文件的进度就是文件上传的进度。

1.首先我们一个类继承RequestBody,不过要重写几个方法
/**
 * requestBody   请求体
 * 文件上传进度回调
 */
class ProgressBody(var requestBody: RequestBody) : RequestBody() {
	//用于监听文件的上传进度回调
    private lateinit var callBack: (Long, Long) -> Unit
    private var mCurrentLength: Long = 0
    constructor(requestBody: RequestBody, callBack: (Long, Long) -> Unit) : this(requestBody) {
        this.callBack = callBack
    }

	/**
	 * 请求体的contentType
	 */
	override fun contentType(): MediaType {
        return requestBody.contentType()!!
    }
    /**
     * 文件写入
     */
    override fun writeTo(sink: BufferedSink?) {
        //获取总长度
        val contentLength = contentLength()

        val forwardingSink = object : ForwardingSink(sink) {
            override fun write(source: Buffer, byteCount: Long) {
                //增加当前写入的字节数
                mCurrentLength += byteCount
                if (callBack != null) {
                	//返回当前进度
                    callBack(mCurrentLength, contentLength)
                }
                super.write(source, byteCount)
            }
        }

        val buffer = Okio.buffer(forwardingSink)
        requestBody.writeTo(buffer)
        // 刷新
        buffer.flush()
    }

	/**
	 * 获取请求体总长度
	 */
    override fun contentLength(): Long {
        return requestBody.contentLength()
    }
}
2.我们简单获取一个OkHttp的实例
class UploadManager constructor(){
	private var okHttpClient: OkHttpClient
	init{
		okHttpClient = OkHttpClient.Builder()
                .connectTimeout(50, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .followRedirects(true)
                .addInterceptor(CommonTokenInterceptor().baseURLInterceptor())
                .retryOnConnectionFailure(true)
                .build()
	}
}
3.我们是上传文件到Oss,所以简单一下表单上传需要的参数
/**
     * 单个上传文件
     * @param policy 上传策略返回
     * @param index 文件索引
     * @param file 文件
     * @param progress 上传进度回调
     * @param complete 上传完成回调
     */
    override fun uploadFileToOss(policy: FormDataPolicy, index: Int,
                                 file: File, progress: (String) -> Unit, @NotNull complete: (FileEntity?) -> Unit,
                                 uploadFail: (String?) -> Unit) {
        val policyResult = policy?.files?.get(index)
                ?: return
        if (TextUtils.isEmpty(policyResult?.key)) {
            complete(policyResult?.file)
            return
        }

        val fileBody = RequestBody.create(MediaType.parse(getMimeType(file.absolutePath)), file)
        val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("OSSAccessKeyId", policy?.accessId)
                .addFormDataPart("Signature", policyResult?.signature)
                .addFormDataPart("callback", policy?.callback)
                .addFormDataPart("key", policyResult?.key)
                .addFormDataPart("policy", policyResult?.policy)
                .addFormDataPart("success_action_status", "200")
                .addFormDataPart("x-oss-forbid-overwrite", "true")
                .addFormDataPart("file", file.name, fileBody)
                .build()

        //回调监听
        val progressBody = ProgressBody(requestBody) { currentLength, ContentLength ->
            progress(((currentLength.toFloat() / ContentLength.toFloat()) * 100).toInt().toString())
        }
        val request = Request.Builder().post(progressBody).url(policy?.host).build()

        val call: Call = okHttpClient.newCall(request)
        call.enqueue(object : Callback {

            override fun onFailure(call: Call?, e: IOException?) {
                uploadFail(e?.message)
            }

            override fun onResponse(call: Call?, response: okhttp3.Response?) {
                if (response?.isSuccessful!!) {
                    val string = response.body().string()
                    val type = object : TypeToken<FileEntity>() {}.type
                    val file = gson.fromJson<FileEntity>(string, type)
                    complete(file)
                } else {
                    complete(null)
                }
            }
        })
    }

这里有部分参数大家可能看的会难受,由于我很懒,直接粘贴过来的,所以了解一下重要部分就好了。
下面代码,获取到文件的请求体 ,重点是最后一部分,如果你用的也是OSS直传,注意addFormDataPart(“key”)一定要在addFormDataPart(“file”)之前。

	val fileBody = RequestBody.create(MediaType.parse(getMimeType(file.absolutePath)), file)
        val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("OSSAccessKeyId", policy?.accessId)
                .addFormDataPart("Signature", policyResult?.signature)
                .addFormDataPart("callback", policy?.callback)
                .addFormDataPart("key", policyResult?.key)
                .addFormDataPart("policy", policyResult?.policy)
                .addFormDataPart("success_action_status", "200")
                .addFormDataPart("x-oss-forbid-overwrite", "true")
                .addFormDataPart("file", file.name, fileBody)
                .build()

然后看这段代码,实现回调监听,ProgressBody中的参数一 一对应,花括号里面的,是kotlin的lambda,这样就能将文件上传的进度回调展示了

//回调监听
val progressBody = ProgressBody(requestBody) { currentLength, ContentLength ->
    progress(((currentLength.toFloat() / ContentLength.toFloat()) * 100).toInt().toString())
}

后面的这部分就是发起请求和响应了

val request = Request.Builder().post(progressBody).url(policy?.host).build()
val call: Call = okHttpClient.newCall(request)
call.enqueue(object : Callback {
      override fun onFailure(call: Call?, e: IOException?) {
          uploadFail(e?.message)
      }
      override fun onResponse(call: Call?, response: okhttp3.Response?) {
          if (response?.isSuccessful!!) {
              val string = response.body().string()
              val type = object : TypeToken<FileEntity>() {}.type
              val file = gson.fromJson<FileEntity>(string, type)
              complete(file)
          } else {
              complete(null)
          }
      }
})
效果图—我这里没有显示数,但是用的进度条展现的

效果图
到此就结束了,成功的完成了文件的上传和进度回调 。
如果帮到了您,给个好评哦!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 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); } } ``` 这个类继承自 OkHttpRequestBody 类,并实现上传文件进度监听。在 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、付费专栏及课程。

余额充值