Android Volley中Listener与Response<ByteArray>报错问题求助
修复Volley自定义ByteArrayRequest的Listener和响应类型错误
核心问题分析
- 父类选择错误:原代码继承
JsonObjectRequest(泛型为JSONObject),但我们需要处理ByteArray类型响应,应直接继承Request<ByteArray>。 - Listener类型不匹配:构造函数中
Response.Listener<Unit>与Request<ByteArray>的泛型不兼容,需统一为Response.Listener<ByteArray>(或按需调整为File类型)。 - parseNetworkResponse返回值错误:返回
Response.success(Unit, ...)不符合Response<ByteArray>的类型要求,需返回对应泛型的成功响应。 - 权限判断冗余:使用
getExternalFilesDir()存储文件属于应用私有外部存储,Android 10+无需WRITE_EXTERNAL_STORAGE权限,可简化权限检查逻辑。 - Activity中语法错误:
errorListener的Lambda表达式语法错误(error -应改为error ->)。
修复后的ByteArrayRequest.kt
import android.content.Context import android.os.Environment import com.android.volley.NetworkResponse import com.android.volley.Request import com.android.volley.Response import com.android.volley.VolleyError import com.android.volley.toolbox.HttpHeaderParser import org.json.JSONObject import java.io.File import java.io.FileOutputStream import java.io.IOException class ByteArrayRequest( private val context: Context, private val fileName: String, method: Int, url: String, private val jsonRequest: JSONObject?, listener: Response.Listener<ByteArray>, errorListener: Response.ErrorListener ) : Request<ByteArray>(method, url, errorListener) { private val headers: MutableMap<String, String> = HashMap() private val responseListener: Response.Listener<ByteArray> = listener fun addHeader(key: String, value: String) { headers[key] = value } override fun parseNetworkResponse(response: NetworkResponse): Response<ByteArray> { val data = response.data // 保存文件到应用私有外部存储 val file = File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName) try { FileOutputStream(file).use { output -> output.write(data) } // 通知监听器下载完成,同时返回字节数组 responseListener.onResponse(data) } catch (e: IOException) { return Response.error(VolleyError(e)) } // 返回字节数组响应,用于缓存或后续处理 return Response.success(data, HttpHeaderParser.parseCacheHeaders(response)) } // 重写getBody,发送JSON请求体 override fun getBody(): ByteArray? { return jsonRequest?.toString()?.toByteArray(charset("UTF-8")) } override fun getBodyContentType(): String { return "application/json; charset=utf-8" } override fun getHeaders(): MutableMap<String, String> { return headers } }
修复后的Activity代码
import android.widget.Toast import com.android.volley.DefaultRetryPolicy import com.android.volley.Request import com.android.volley.Volley import org.json.JSONException import org.json.JSONObject fun submitdata(url: String) { val js = JSONObject() try { js.put("year", financialyear!!.selectedItem.toString().toInt()) js.put("month", month!!.selectedItem.toString().toInt()) js.put("emp_number", emp_num) Log.d("volley","js:${js}") } catch (e: JSONException) { e.printStackTrace() } val byteArrayRequest = ByteArrayRequest( context = applicationContext, fileName = "report.pdf", method = Request.Method.POST, url = url, jsonRequest = js, listener = { byteArray -> // 下载完成,可在这里处理字节数组或直接打开文件 val file = File(applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "report.pdf") Toast.makeText(applicationContext, "文件已保存至: ${file.path}", Toast.LENGTH_LONG).show() // 如需预览PDF,可在这里启动PDF查看器 }, errorListener = { error -> Log.d("volley","Error:${error.message}") Toast.makeText(applicationContext, "下载失败: ${error.message}", Toast.LENGTH_SHORT).show() } ) byteArrayRequest.retryPolicy = DefaultRetryPolicy( 100000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT ) byteArrayRequest.addHeader("Authorization", "Bearer " + SharedPrefrence.getApitoken(applicationContext)) byteArrayRequest.addHeader("x-api-key", SharedPrefrence.getApikey(applicationContext)!!) val requestQueue = Volley.newRequestQueue(applicationContext) requestQueue.add(byteArrayRequest) }
额外说明
- 如果不需要返回字节数组,只想在下载完成后通知文件路径,可以将
ByteArrayRequest的泛型改为File,并在parseNetworkResponse中返回Response.success(file, ...),同时调整Listener为Response.Listener<File>。 - Android 10及以上版本,
getExternalFilesDir()路径无需权限,若需兼容Android 9及以下,可保留权限检查逻辑,但注意动态申请权限。
内容的提问来源于stack exchange,提问作者jyothihayathi g
相关产品推荐
相关产品推荐

