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
    评论
你可以使用Retrofit进行网络请求,并使用OkHttp拦截器来实现上和下载速率的测量。以下是一个示例: 首先,添加依赖: ```groovy implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' ``` 然后,创建一个Retrofit实例: ```java OkHttpClient.Builder httpClient = new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public okhttp3.Response intercept(Chain chain) throws IOException { Request original = chain.request(); Request.Builder requestBuilder = original.newBuilder() .method(original.method(), original.body()); Request request = requestBuilder.build(); return chain.proceed(request); } }) .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)); Retrofit retrofit = new Retrofit.Builder() .baseUrl("YOUR_BASE_URL") .client(httpClient.build()) .addConverterFactory(GsonConverterFactory.create()) .build(); ``` 接下来,创建一个API接口: ```java public interface ApiService { @Multipart @POST("YOUR_ENDPOINT") Call<ResponseBody> uploadFile(@Part MultipartBody.Part file); } ``` 最后,执行网络请求并测量上速度: ```java File file = new File("YOUR_FILE_PATH"); RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), requestBody); ApiService service = retrofit.create(ApiService.class); Call<ResponseBody> call = service.uploadFile(filePart); long startTime = System.currentTimeMillis(); call.execute(); long endTime = System.currentTimeMillis(); long duration = endTime - startTime; long fileSize = file.length(); double speed = (double) fileSize / duration; Log.d("UPLOAD_SPEED", "Speed: " + speed + " bytes/ms"); ``` 注意:这只是一个简单的示例代码,你可能需要根据你的具体情况进行适当的调整。此外,测量下载速度的方法与上速度的方法类似。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值