使用Volley从MySQL获取数据到RecyclerView失败排查求助
Android Volley加载MySQL数据到RecyclerView失败问题排查与修复
在Android中使用Volley通过JSON数组从MySQL获取id为1的所有行数据并加载到RecyclerView时,出现无法将字符串转换为JSON数组的错误,导致数据无法加载。以下是问题排查和修复方案:
一、核心错误点分析
- PHP语法错误:原PHP代码末尾
echo json_encode($all_jobs)缺少分号,会导致PHP解析失败,输出非合法JSON内容。 - 响应头缺失:未设置
Content-Type: application/json,Volley无法正确识别响应类型,增加解析失败概率。 - SQL注入风险+错误处理缺失:直接拼接
$_POST['id']到SQL语句存在注入风险,且未处理数据库连接、查询失败场景,可能输出错误信息破坏JSON格式。 - Android端未更新适配器:数据添加到集合后未调用适配器的
notifyDataSetChanged(),即使加载成功RecyclerView也不会更新。 - 字符编码问题:PHP输出JSON未指定编码,含非ASCII字符时可能导致解析失败。
二、修复后的代码
1. 修复后的PHP代码
<?php header("Content-Type: application/json; charset=utf-8"); // 设置响应头与编码 require_once "conn.php"; require_once "validate.php"; // 安全获取POST参数并防注入 $id = isset($_POST['id']) ? mysqli_real_escape_string($conn, $_POST['id']) : ''; if(empty($id)){ echo json_encode(array("error" => "参数错误")); exit; } // 使用预处理语句彻底避免SQL注入 $sql = "SELECT * from all_jobs WHERE id = ?"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, "s", $id); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $all_jobs = array(); while($row = mysqli_fetch_assoc($result)){ $index = array( 'jobname' => $row['jobname'], 'posts' => $row['posts'], 'startdate' => $row['startdate'], 'enddate' => $row['enddate'], 'govtfees' => $row['govtfees'], 'appfees' => $row['appfees'], 'documents' => $row['documents'], 'declartion' => $row['declartion'], 'jobdetails' => $row['jobdetails'] ); array_push($all_jobs, $index); } // 输出带中文支持的JSON echo json_encode($all_jobs, JSON_UNESCAPED_UNICODE); mysqli_stmt_close($stmt); mysqli_close($conn); ?>
2. 修复后的Android代码
private void LoadAllJobs() { StringRequest stringRequest = new StringRequest(Request.Method.POST, Urls.all_jobs, new Response.Listener<String>() { @Override public void onResponse(String response) { try { Log.d("VolleyDebug", "接口返回内容: " + response); // 打印响应便于排查 JSONArray jsonArray = new JSONArray(response); allJobs.clear(); // 清空旧数据避免重复加载 for (int i = 0; i < jsonArray.length(); i++) { JSONObject object = jsonArray.getJSONObject(i); String jobname = object.getString("jobname"); String jobdetails = object.getString("jobdetails"); String startdate = object.getString("startdate"); String enddate = object.getString("enddate"); String posts = object.getString("posts"); String govtfees = object.getString("govtfees"); String appfees = object.getString("appfees"); String documents = object.getString("documents"); String declartion = object.getString("declartion"); AllJobsModel jobModel = new AllJobsModel( jobname, jobdetails, posts, startdate, enddate, govtfees, appfees, documents, declartion); allJobs.add(jobModel); } yourRecyclerViewAdapter.notifyDataSetChanged(); // 通知适配器更新 AndroidUtil.showToast(getApplicationContext(), "数据加载成功"); } catch (JSONException e) { e.printStackTrace(); AndroidUtil.showToast(getApplicationContext(), "JSON解析失败: " + e.getMessage()); Log.e("JSONError", "解析失败的响应内容: " + response); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { error.printStackTrace(); AndroidUtil.showToast(getApplicationContext(), "网络请求失败: " + error.getMessage()); } }) { @Nullable @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> params = new HashMap<>(); params.put("id", "1"); return params; } }; // 设置超时与重试策略 stringRequest.setRetryPolicy(new DefaultRetryPolicy( 5000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); RequestQueue queue = Volley.newRequestQueue(MainActivity.this); queue.add(stringRequest); }
三、额外排查建议
- 直接测试PHP接口:用Postman发送POST请求,查看返回内容是否为标准JSON格式,是否包含错误提示。
- 查看PHP日志:检查服务器PHP错误日志,确认是否有数据库连接、语法等问题。
- 检查Android日志:通过Logcat查看Volley返回的原始响应内容,判断是否有多余字符破坏JSON结构。
内容的提问来源于stack exchange,提问作者forline
相关产品推荐
相关产品推荐

