Android Marshmallow以上版本Retrofit 2 Multipart API报错问题
解决Retrofit 2 Multipart在Android Marshmallow+设备抛出的IllegalStateException问题
我之前也碰到过一模一样的情况,这个问题的核心其实和Android 6.0开始的动态权限机制脱不了干系,当然也可能和文件本身的有效性有关,咱们一步步拆解:
问题根源
- 动态权限缺失:Android 6.0(API 23)起,读取外部存储的权限(
READ_EXTERNAL_STORAGE)属于危险权限,必须在运行时主动申请,光靠Manifest声明没用。如果你的App在Marshmallow+设备上没拿到这个权限,代码里File file = new File(filePaths.get(i))不会直接报错,但后续尝试读取文件(比如创建RequestBody、获取文件信息)会失败,导致循环里根本没往MultipartBody.Builder里添加任何part,最后build时就会抛出Multipart body must have at least one part的异常。 - 无效文件路径:也有可能是部分文件路径在高版本系统中受限于Scoped Storage无法访问,或者文件本身已被删除,导致循环中没有有效文件被添加到builder中。
解决方案
1. 先确保拿到动态权限
在执行上传逻辑前,先检查并申请存储权限:
// 检查是否已获取存储权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // 弹出权限申请对话框 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION_CODE); return; } // 权限已获取,执行上传 uploadFiles(filePaths);
2. 校验文件有效性,避免空part
循环添加文件前,先检查文件是否存在且为有效文件:
MultipartBody.Builder builder = new MultipartBody.Builder(); builder.setType(MultipartBody.FORM); try { for (int i = 0; i < filePaths.size(); i++) { File file = new File(filePaths.get(i)); // 先校验文件有效性 if (file.exists() && file.isFile() && file.length() > 0) { String mFileName = App.getInstance().getPrefs().getUserId() + "_" + new Date().getTime() + "_" + i; // 添加文件part到builder builder.addFormDataPart("files[]", mFileName, RequestBody.create(MediaType.parse("multipart/form-data"), file)); } } } catch (Exception e) { e.printStackTrace(); } // 兜底检查:确保builder至少有一个part再提交请求 MultipartBody requestBody = builder.build(); if (requestBody.parts().isEmpty()) { // 提示用户没有可上传的有效文件 Toast.makeText(this, "未找到可上传的有效文件", Toast.LENGTH_SHORT).show(); return; } // 继续执行Retrofit请求逻辑 // ...
3. 适配Android 10+的Scoped Storage
如果你的App面向Android 10(API 29)及以上版本,直接通过文件路径访问外部存储可能会受限,建议使用MediaStore或存储访问框架(SAF)来获取文件,避免路径无效的问题。
总结
这个问题本质是高版本Android权限和存储机制变化导致的,只要确保权限到位、文件有效,再加上兜底检查,就能解决这个异常啦。
内容的提问来源于stack exchange,提问作者Ramesh sambu
相关产品推荐
相关产品推荐

