Android 9 Pie(API28)空对象引用问题排查求助
这个问题我太熟悉了——在Android 8上跑的好好的,到Android 9就炸了,核心原因是Android 9(API 28)开始默认禁用了明文HTTP请求。你的代码里用HttpURLConnection访问HTTP接口的话,请求会直接失败,导致doInBackground返回null,后续把null传给JSONArray构造器,就触发了String.length()的空指针异常。
第一步:确认问题根源
API 28及以上系统中,Google为了提升安全性,默认阻止App发起明文(非HTTPS)的网络请求。你的doInBackground方法里,请求失败时会返回null,然后在onPostExecute里直接把这个null传给loadIntoListView,new JSONArray(json)这一步就会因为json是null,内部调用String.length()时抛出异常。
第二步:修复方案
这里有两种常用解决方式,优先推荐第一种:
方案1:升级接口为HTTPS(强烈推荐)
这是最安全、符合Google规范的做法,把你的urlWebService换成HTTPS地址,直接绕过明文请求限制,问题就能解决。
方案2:允许明文HTTP请求(临时过渡方案)
如果暂时无法升级HTTPS,可以通过配置让App允许明文请求:
- 快速方式:在
AndroidManifest.xml的<application>标签里添加属性:<application ... android:usesCleartextTraffic="true"> - 更安全的方式(针对特定域名开放):
- 在
res/xml目录下创建network_security_config.xml,内容如下:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <!-- 替换成你的接口域名 --> <domain includeSubdomains="true">your-api-domain.com</domain> </domain-config> </network-security-config> - 在
AndroidManifest.xml的<application>标签里引用这个配置:<application ... android:networkSecurityConfig="@xml/network_security_config">
- 在
第三步:优化代码,避免后续崩溃
除了网络配置问题,你的代码缺少空值判断,就算网络请求成功,也可能因为JSON格式不正确崩溃。建议修改这几处:
修改
doInBackground,异常时返回空字符串而非null:@Override protected String doInBackground(Void... voids) { try { URL url = new URL(urlWebService); HttpURLConnection con = (HttpURLConnection) url.openConnection(); StringBuilder sb = new StringBuilder(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream())); String json; while ((json = bufferedReader.readLine()) != null) { sb.append(json + "\n"); } return sb.toString().trim(); } catch (Exception e) { e.printStackTrace(); // 打印异常方便调试 return ""; // 返回空字符串代替null } }在
onPostExecute里先判断返回值是否有效:@Override protected void onPostExecute(String s) { super.onPostExecute(s); if (s == null || s.isEmpty()) { Toast.makeText(getApplicationContext(), "请求失败或无数据", Toast.LENGTH_SHORT).show(); return; } try { loadIntoListView(s); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "JSON解析失败", Toast.LENGTH_SHORT).show(); } }在
loadIntoListView里增加空值判断,并用optString避免key不存在崩溃:private void loadIntoListView(String json) throws JSONException { if (json.isEmpty()) { // 处理空数据情况,比如显示空提示 listView.setAdapter(null); Toast.makeText(this, "暂无数据", Toast.LENGTH_SHORT).show(); return; } JSONArray jsonArray = new JSONArray(json); String[] stocks = new String[jsonArray.length()]; for (int i = 0; i < jsonArray.length(); i++) { JSONObject obj = jsonArray.getJSONObject(i); // 用optString设置默认值,避免key不存在时崩溃 String sentDate = obj.optString("sent_date", "未知时间"); String username = obj.optString("username", "匿名用户"); String message = obj.optString("message", "无内容"); stocks[i] = sentDate + "| " + username + ": " + message; } ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, stocks); listView.setAdapter(arrayAdapter); }
这样修改后,不仅解决了Android 9的明文请求问题,还增强了代码的健壮性,能应对网络异常、JSON格式错误等多种情况。
内容的提问来源于stack exchange,提问作者Valentin Gjorgoski

