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

如何在Android Studio中使用VolleyMultipart在单次请求中上传多个文件

实现单次请求上传多个文件的改造方案

1. 改造上传函数,支持多文件批量传入

将原本接收单个文件的上传函数调整为接收文件名+Uri的集合,批量读取所有文件字节后塞入 multipart 请求参数:

// 入参修改为 文件名-URI 集合
private fun uploadFiles(fileList: List<Pair<String, Uri>>) {
    var rQueue = Volley.newRequestQueue(this)
    val myurl = "https://apiurl"
    try {
        val filePartMap: MutableMap<String, DataPart> = HashMap()
        // 批量读取所有文件字节,存入参数Map
        fileList.forEachIndexed { index, (fileName, uri) ->
            val iStream = contentResolver.openInputStream(uri)
            val inputData = getBytes(iStream)
            // 注意:参数名需要和你服务端约定的多文件接收字段匹配
            // 如果服务端接收数组格式,参数名用 evidence_image[$index] 或者 evidence_image[]
            filePartMap["evidence_image_$index"] = DataPart(fileName, inputData)
        }

        val volleyMultipartRequest: VolleyMultipartRequest = object : VolleyMultipartRequest(
            Method.POST, myurl,
            Response.Listener { response ->
                try {
                    val jsonobject = JSONObject(String(response.data))
                    val returnmsg = jsonobject.getString("hua ki nhi")
                    if(returnmsg == "aish kro ho gya")
                    {
                        Toast.makeText(this, "所有文件上传成功", Toast.LENGTH_SHORT).show()
                    }
                    else{
                        Toast.makeText(this, "文件上传失败", Toast.LENGTH_SHORT).show()
                    }
                    dialog.cancel()
                }catch (e: JSONException){
                    e.printStackTrace()
                    dialog.cancel()
                }
            },
            Response.ErrorListener { error ->
                Toast.makeText(
                    applicationContext,
                    error.message,
                    Toast.LENGTH_SHORT
                ).show()
                dialog.cancel()
            }) {

            @Throws(AuthFailureError::class)
            override fun getParams(): Map<String, String>? {
                // 按需添加其他普通参数
                return HashMap()
            }

            override fun getByteData(): Map<String, DataPart> {
                return filePartMap
            }
        }
        // 多文件上传体积大,建议调整超时时间为30秒,避免中途超时
        volleyMultipartRequest.retryPolicy = DefaultRetryPolicy(
            30000,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
            DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
        )
        rQueue.add(volleyMultipartRequest)
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

@Throws(IOException::class)
fun getBytes(inputStream: InputStream?): ByteArray {
    val byteBuffer = ByteArrayOutputStream()
    val bufferSize = 1024
    val buffer = ByteArray(bufferSize)
    var len = 0
    while (inputStream!!.read(buffer).also { len = it } != -1) {
        byteBuffer.write(buffer, 0, len)
    }
    return byteBuffer.toByteArray()
}

2. 完善文件选择结果处理逻辑

在onActivityResult中兼容单选、多选两种情况,收集所有选中的文件后调用批量上传函数:

attachbtn.setOnClickListener {
    val mimeTypes = arrayOf("image/*", "application/pdf")
    val intent = Intent()
    intent.type = "*/*"
    intent.action = Intent.ACTION_GET_CONTENT
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
    intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
    startActivityForResult(Intent.createChooser(intent, "选择文件"), 111)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 111 && resultCode == Activity.RESULT_OK && data != null) {
        val fileList = mutableListOf<Pair<String, Uri>>()
        // 处理多选情况
        if (data.clipData != null) {
            val mulfile = data.clipData!!
            val itemcount = mulfile.itemCount
            for (i in 0 until itemcount) {
                val uri = mulfile.getItemAt(i).uri
                // 可自行实现从Uri获取原文件名的逻辑,此处用时间戳作为示例
                val fileName = "file_${System.currentTimeMillis()}_$i"
                fileList.add(Pair(fileName, uri))
            }
        } 
        // 处理单选情况
        else if (data.data != null) {
            val uri = data.data!!
            val fileName = "file_${System.currentTimeMillis()}"
            fileList.add(Pair(fileName, uri))
        }
        // 调用批量上传
        if (fileList.isNotEmpty()) {
            uploadFiles(fileList)
        }
    }
}

注意事项

  • 多文件参数名需要和服务端约定的接收字段完全匹配,如果服务端要求接收数组格式的字段,可将参数名改为evidence_image[]或者evidence_image[下标]
  • 如果需要上传的文件总大小过大,一次性将所有文件读入内存可能触发OOM,这种场景建议改用分块上传方案
  • 可根据实际业务需求调整重试策略的超时时间和重试次数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:45:03