Uri:通用资源标志符(Universal Resource Identifier, 简称"URI")。
Uri在安卓系统中应用很广泛,系统返回的文件一般都是Uri类型的无法直接读取,以往的办法是通过contentResolver
读取到文件的真实路径,然后上传这个文件。麻烦不说,兼容性也没法保证。
通过阅读okhttp源码,模仿File的扩展方法给Uri也实现了一个扩展:
@SuppressLint("Recycle")
fun Uri.openInputStream(context:Context): InputStream? {
val contentResolver = context.contentResolver
return contentResolver.openInputStream(this)
?: contentResolver.openAssetFileDescriptor(this, "r")?.createInputStream()
}
fun Uri.asRequestBody(context:Context,contentType: MediaType? = null): RequestBody {
return object : RequestBody() {
override fun contentType(): MediaType? {
return contentType
}
override fun writeTo(sink: BufferedSink) {
openInputStream(context)?.run {
source().use {
sink.writeAll(it)
}
}
}
}
}
使用示例,retrofit
同理:
val uri = xxx
val httpClient = OkHttpClient()
val request = Request.Builder()
.put(uri.asRequestBody(context))
.url(xxx)
.build()
httpClient.newCall(request).execute()
使用的时候需要注意几点:
- 拥有这个uri的读取权限,如果没有申请读写外部存储的权限就去读取sd卡文件那肯定不行。
- 确保uri本身是文件类型的,一般文件uri的scheme是file,例如
file:///sdcard/download/123.mp3
。