You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin使用Multipart和RequestBody上传图片返回null问题求助

问题根因与修复方案

核心问题1:异步线程导致返回值未初始化

你在getImageRequestBody方法中开启了独立子线程执行赋值逻辑,但主线程不会等待子线程执行完成,会直接返回初始值null。且获取MimeType、创建RequestBody属于轻量操作,完全不需要额外开子线程。

核心问题2:RequestBody创建逻辑错误

当前代码使用sourceFile.path.toRequestBody(),仅将文件路径字符串封装为请求体,并未读取文件本身的二进制内容,完全无法实现文件上传效果。

核心问题3:MediaType配置错误

单文件请求体的MediaType应使用图片对应的MimeType,而非multipart/form-data,后者是整个Multipart请求的全局类型。

修复后的代码

1. 修正GalleryCameraUtility工具类

class GalleryCameraUtility {
    companion object{
        fun getImageRequestBody(sourceFile: File) : RequestBody? {
            val mimeType = getMimeType(sourceFile) ?: run {
                Log.e("file error", "Not able to get mime type")
                return null
            }
            return try {
                // 直接读取文件内容生成RequestBody
                sourceFile.asRequestBody(mimeType.toMediaTypeOrNull())
            } catch (ex: Exception) {
                ex.printStackTrace()
                Log.e("File upload", "failed")
                null
            }
        }

        private fun getMimeType(file: File): String? {
            var type: String? = null
            val extension = MimeTypeMap.getFileExtensionFromUrl(file.path)
            if (extension != null) {
                type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.lowercase())
            }
            return type
        }
    }
}

2. 补充Multipart参数封装(适配Retrofit接口)

如果你的Retrofit上传接口使用@Multipart注解,建议将文件封装为MultipartBody.Part传递,示例如下:
Retrofit接口定义:

@Multipart
@POST("你的接口地址")
fun addNewCompanyApi(
    @Part("company_name") companyName: RequestBody,
    @Part("email") email: RequestBody,
    @Part imageFile: MultipartBody.Part,
    @Part("owner_name") ownerName: RequestBody,
    @Part("address") address: RequestBody,
    @Part("user_id") userId: RequestBody
): Call<你的响应实体类>

参数封装逻辑:

fun addNewCompany(companyName: String, email: String,imageFile: File, ownerName: String, address: String, companyDetails: String){
    // 先验证文件有效性
    if (!imageFile.exists() || imageFile.length() <= 0) {
        Log.e("upload error", "文件无效")
        return
    }

    val companyNameBody: RequestBody = companyName.toRequestBody("text/plain".toMediaType())
    val emailBody: RequestBody = email.toRequestBody("text/plain".toMediaType())
    val fileData: RequestBody? = GalleryCameraUtility.getImageRequestBody(imageFile)
    // 封装为Multipart.Part,第一个参数为服务端接收文件的字段名
    val imagePart = MultipartBody.Part.createFormData(
        "server端接收文件的key",
        imageFile.name,
        fileData ?: return
    )
    val ownerNameBody: RequestBody = ownerName.toRequestBody("text/plain".toMediaType())
    val addressBody: RequestBody = address.toRequestBody("text/plain".toMediaType())
    val userIdBody: RequestBody = PreferenceHelper.readUserIdPref(Constants.USER_ID).toString()
        .toRequestBody("text/plain".toMediaType())

    addCompanyRepo.addNewCompanyApi(companyNameBody, emailBody, imagePart, ownerNameBody, addressBody, userIdBody)
}

额外检查项

  • 确认已申请对应存储权限:Android 13及以上需申请READ_MEDIA_IMAGES,Android 12及以下需申请READ_EXTERNAL_STORAGE
  • 不要在主线程直接执行网络请求,使用Retrofit自带的异步enqueue方法或协程切换到IO线程执行

内容的提问来源于stack exchange,提问作者Dnveeraj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 12:06:05