Android 10 使用OkHttp4和Retrofit上传图片

作者:Angki  
转载请注明


最近发现项目在Android 10下,上传图片报错

open failed: EACCES (Permission denied)

上网查了下,是由于Android 10的文件存储机制修改成了沙盒模式,应用不能直接访问除了沙盒文件和公共文件以外的文件,直接使用图片绝对地址上传图片会出错。最简单的解决办法就是在AndroidManifest.xml中添加

android:requestLegacyExternalStorage="true"

但是,这方式只是临时解决而已,Google也说明了在Android 11 中这种临时的解决办法也会失效。为了以后方便,直接就是用Google推荐的方式进行适配。

由于项目网络框架使用OkHttp4和Retrofit,只要把上传需要的MultipartBody对象构建出来就行了,之前的写法:

val file = File(图片的绝对地址)
//传输图片
val img = file.asRequestBody("image/png".toMediaType())
//MultipartBody
val request = MultipartBody.Builder()
    .addFormDataPart("file", "${TimeUtils.getNowMills()}.png", img)
    .build()

适配后的写法

var file: ByteArray? = null
contentResolver.openInputStream(图片的Uri).use {
    file = it?.readBytes()
}
file?.let {
    val img = it.toRequestBody("image/png".toMediaType())
    val request = MultipartBody.Builder()
        .addFormDataPart("file", "${TimeUtils.getNowMills()}.png", img)
        .build()
    mViewModel.uploadImage(request)
}

之前的写法和适配后的写法差别就是在于RequestBody的获取。在适配过程中,陷入了一个误区,就是要先获取File文件,然后使用OkHttp提供的方法来获取RequestBody。

fun File.asRequestBody(contentType: MediaType? = null): RequestBody 

然后就找方法来获取File,但是只找到了通过Uri获取Bitmap,我就在想着先获取Bitmap,然后把Bitmap转换成File文件。幸运的是,我看见了OkHttp提供的其他方法来获取RequestBody。

fun String.toRequestBody(contentType: MediaType? = null): RequestBody
fun ByteString.toRequestBody(contentType: MediaType? = null): RequestBody
fun ByteArray.toRequestBody(
    contentType: MediaType? = null,
    offset: Int = 0,
    byteCount: Int = size
    ): RequestBody

再结合在官网看见的获取文件的流方法:

// Open a specific media item using InputStream.
val resolver = applicationContext.contentResolver
resolver.openInputStream(content-uri).use { stream ->
    // Perform operations on "stream".
}

最后就有了适配的写法,测试了一下,没得问题。最后得出一个结论,我是菜狗…

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值