HttpLoggingInterceptor
拦截器是个好东西, 查看retrofit请求和上传进度回调都靠它。
val loggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
// 打印retrofit日志
Log.i("RetrofitLog", "retrofitBack = $it")
})
// 不要设置成BODY,会导致writeTo调用两次
loggingInterceptor.level = HttpLoggingInterceptor.Level.HEADERS
level 不要设置成Body,会导致下载进度回调执行两次。
val httpClient = OkHttpClient.Builder()
// .cache(cache)
.addInterceptor(loggingInterceptor)
.connectTimeout(NETWORK_CALL_TIMEOUT.toLong(), TimeUnit.SECONDS)
.readTimeout(NETWORK_CALL_TIMEOUT.toLong(), TimeUnit.SECONDS)
.writeTimeout(NETWORK_CALL_TIMEOUT.toLong(), TimeUnit.SECONDS)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(BaseUrlConstants.getBaseUrl(BaseUrlConstants.BaseUrlType.API))
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
继承Callback
abstract class RetrofitCallback: Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
onSuccess(call, response)
} else {
onFailure(call, Throwable(response.message()) as IOException?)
}
}
abstract fun onSuccess(call: Call, response: Response)
abstract fun onLoading(total: Long, progress: Long)
}
主要是为了增加onLoading的回调
继承RequestBody
class FileRequestBody(
private val requestBody: RequestBody,
private val callback: RetrofitCallback
) : RequestBody() {
/**
* 包装完成的BufferedSink
*/
private var bufferedSink: BufferedSink? = null
@Throws(IOException::class)
override fun contentLength(): Long {
return requestBody.contentLength()
}
override fun contentType(): MediaType {
return requestBody.contentType()
}
@Throws(IOException::class)
override fun writeTo(sink: BufferedSink) {
bufferedSink = Okio.buffer(sink(sink))
//写入
requestBody.writeTo(bufferedSink)
//必须调用flush,否则最后一部分数据可能不会被写入
bufferedSink!!.flush()
}
/**
* 写入,回调进度接口
*/
private fun sink(sink: Sink): Sink {
return object : ForwardingSink(sink) {
//当前写入字节数
internal var bytesWritten = 0L
//总字节长度,避免多次调用contentLength()方法
internal var contentLength = 0L
@Throws(IOException::class)
override fun write(source: Buffer, byteCount: Long) {
super.write(source, byteCount)
if (contentLength == 0L) {
//获得contentLength的值,后续不再调用
contentLength = contentLength()
}
//增加当前写入的字节数
bytesWritten += byteCount
//回调
callback.onLoading(contentLength, bytesWritten)
}
}
}
}
注意重写的writeTo方法,如果把拦截级别设置成Body会导致该方法执行两次。
上传封装
以上传图片为例
fun uploadImage(file: File, type: Int, retrofitCallback: RetrofitCallback, subscriber: Consumer<ApiResponse<String>>) {
Observable
.just(file)
.map {
val requestBody = RequestBody.create(MediaType.parse("image/png"), it)
val fileRequestBody = FileRequestBody(requestBody, retrofitCallback)
MultipartBody.Part.createFormData("file", file.name, fileRequestBody)
}
.subscribe {
AppApiHelper
.create(UploadDocumentService::class.java)
.uploadPicture(activity.access, it, type)
.subscribeOn(Schedulers.io())
.subscribe(subscriber)
}
}
调用示例
fun getPictureUri(file: File) {
dialogManager.mdProgress("上传中...", true)
uploadImage( file, type, object : RetrofitCallback() {
override fun onSuccess(call: Call, response: Response) {
Log.e("retrofit", "response: $response")
}
override fun onLoading(total: Long, progress: Long) {
Log.e("retrofit", "total: $total ; progress: $progress")
val p = (progress * 100 / total).toInt()
dialogManager.updateProgress(p, 100, "", true)
if (p == 100) {
SystemClock.sleep(200)
dialogManager.dialog.dismiss()
}
}
override fun onFailure(call: Call?, e: IOException) {
Log.e("retrofit", "e: $e")
}
},
Consumer {
if (networkUtil.checkResponse(it)) {
activity.toastDebug(it.data ?: "上传成功")
} else {
activity.toastDebug(it.message ?: "上传失败")
}
}
)
}
此处用的是我自行封装的dialog,睡200毫秒是为了在小文件上传的时候也能看见一点上传进度条。
网友评论