Android Volley请求频繁抛NoConnection/EOFException及JSON解析异常求助
看起来你在使用Volley的StringRequest发起POST请求时遇到了一堆头疼的问题——频繁的连接异常偶尔才能拿到数据,还有JSON解析报错。我来帮你一步步排查这些问题:
一、先解决网络连接类异常(NoConnection Error、EOFException)
这些异常通常和请求的基础配置、网络环境或者服务器端的要求有关,你可以按下面的步骤排查:
检查请求端点的有效性
首先确认UrlEndPoints.interAd这个URL是完全正确的,包括协议(http/https)、域名和路径。如果你的应用是Android 9及以上版本,默认是禁止HTTP明文请求的,要是后端用的是HTTP,你需要在AndroidManifest.xml的<application>标签里添加:android:usesCleartextTraffic="true"或者配置更安全的
network_security_config.xml来允许特定域名的明文请求。验证请求参数的正确性
在getParams()方法里添加日志,确认你传递的参数是否符合后端的要求:@Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<>(); params.put("task", "get_interad_apps"); String packageName = getPackageName(); params.put("package", packageName); // 打印参数确认 Log.d("VolleyParams", params.toString()); return params; }重点确认:后端是否期望
package这个字段名?会不会是package_name或者其他名称?另外getPackageName()返回的包名是否正确?检查Volley的请求头配置
StringRequest默认的Content-Type是application/x-www-form-urlencoded,如果后端要求的是application/json,那用getParams()传递参数是无效的,这时候需要重写getBody()和getHeaders():@Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); return headers; } @Override public byte[] getBody() throws AuthFailureError { try { JSONObject params = new JSONObject(); params.put("task", "get_interad_apps"); params.put("package", getPackageName()); return params.toString().getBytes("utf-8"); } catch (Exception e) { return null; } }排查服务器端和网络环境
试试用Postman或者curl直接调用这个接口,看看能不能正常返回数据。如果Postman也有问题,那大概率是后端的问题(比如接口限流、服务器不稳定)。另外换个网络环境测试(比如从WiFi换成手机流量),排除代理或者网络波动的影响。
二、解决JSON解析异常
JSON解析报错通常是因为返回的响应格式不符合预期,或者你的解析逻辑有问题:
先确认响应的真实内容
在onResponse的最开头,把完整的response打印出来,看看是不是有效的JSON:@Override public void onResponse(String response) { Log.d("FullResponse", "Raw response: " + response); // 后续的解析逻辑... }很多时候出现解析异常,是因为后端返回的不是JSON,而是HTML错误页面(比如404、500错误),或者返回的JSON格式有语法错误(比如多余的逗号、引号不匹配)。
优化JSON解析逻辑,增加容错性
不要直接用getInt()、getString()这些方法,改用optInt()、optString()来避免字段不存在或者为空时抛出异常,同时检查JSON结构是否符合预期:try { JSONObject jsonObject = new JSONObject(response); Log.e("jObj_AppURL", jsonObject.toString()); // 用optInt,指定默认值 int success = jsonObject.optInt(SUCCESS, 0); if (success == 1) { // 先判断是否存在RESPONSE数组,避免空指针 JSONArray data = jsonObject.optJSONArray(RESPONSE); if (data != null && data.length() > 0) { for (int i = 0; i < data.length(); i++) { JSONObject c = data.optJSONObject(i); if (c != null) { // 用optString,空值时返回空字符串 appImg = c.optString(APPIMG, ""); appName = c.optString(APPNAME, ""); appPackages = c.optString(PKG, ""); InterAdModel interAdModel = new InterAdModel(); interAdModel.setAppImg(appImg); interAdModel.setAppName(appName); interAdModel.setAppPackages(appPackages); interAdModelArrayList.add(interAdModel); } } } } } catch (JSONException e) { Log.e("JSONParseError", "解析失败: " + e.getMessage()); e.printStackTrace(); }另外要确认
SUCCESS、RESPONSE、APPIMG这些常量的字符串值,和后端返回的JSON字段名完全一致(包括大小写),比如后端返回的是"success"而你定义的SUCCESS是"SUCCESS",就会导致解析失败。
额外的调试建议
- 在
onErrorResponse里打印更详细的错误信息,比如:
这样能看到服务器返回的状态码和错误响应体,更容易定位问题。@Override public void onErrorResponse(VolleyError error) { Log.e("VolleyError", "错误详情: ", error); if (error.networkResponse != null) { Log.e("Status Code", String.valueOf(error.networkResponse.statusCode)); String errorBody = new String(error.networkResponse.data); Log.e("Error Body", errorBody); } Toast.makeText(SplashActivity.this, "请求失败: " + error.getMessage(), Toast.LENGTH_LONG).show(); }
内容的提问来源于stack exchange,提问作者Pooja Pachchigar

