Android Java页面OkHttp获取JSON成功但ListView不显示数据
问题根因
列表空白核心是网络请求时序逻辑写错了:
- 你在
AsyncTask的doInBackground里调用OkHttp的enqueue发异步请求,这个方法是非阻塞的,请求会丢给OkHttp自己的线程池执行,doInBackground会立刻执行return null,马上触发onPostExecute。 - 这时候OkHttp的响应还没回来,
resultList是空的,你把空集合传给SimpleAdapter绑定ListView,当然显示空白。等后续回调把数据塞进resultList的时候,Adapter早就初始化完成了,感知不到数据变化,不会刷新界面。
另外还有几个隐患:
- 子线程直接修改
resultList没有加同步,存在并发修改风险 - 重复导入
java.util.ArrayList,还有Gson、SearchView、ArrayAdapter等一堆没用到的冗余导入,虽然不影响运行但没必要留 - OkHttp回调本身在子线程,就算数据加载完你直接更新UI也会崩溃,必须切主线程
修复方案
两种改法二选一,不要混着写多套异步逻辑:
方案1:OkHttp改同步调用,适配现有AsyncTask逻辑
去掉enqueue异步回调,直接用OkHttp同步方法execute(),在doInBackground里直接完成响应读取、JSON解析,等所有数据处理完再返回,这样onPostExecute执行的时候resultList里已经有完整数据了。
doInBackground修改后核心代码:
@Override protected Void doInBackground(Void... arg0) { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://heisenbug-premier-league-live-scores-v1.p.rapidapi.com/api/premierleague/team?name=Liverpool") .get() .addHeader("X-RapidAPI-Key", "替换成你自己的有效Key") .addHeader("X-RapidAPI-Host", "heisenbug-premier-league-live-scores-v1.p.rapidapi.com") .build(); try { Response response = client.newCall(request).execute(); if (!response.isSuccessful()) return null; String jsonStr = response.body().string(); Log.e(TAG, "Response from url: " + jsonStr); if (jsonStr == null) return null; JSONObject jsonObj = new JSONObject(jsonStr); JSONArray records = jsonObj.getJSONArray("records"); for (int i = 0; i < records.length(); i++) { JSONObject c = records.getJSONObject(i); HashMap<String, String> result = new HashMap<>(); result.put("league",c.getString("league")); result.put("season",c.getString("season")); result.put("name",c.getString("name")); result.put("officialName",c.getString("officialName")); result.put("address",c.getString("address")); result.put("telephone",c.getString("telephone")); result.put("fax",c.getString("fax")); result.put("website",c.getString("website")); result.put("founded",c.getString("founded")); result.put("teamSize",c.getString("teamSize")); result.put("averageAge",c.getString("averageAge")); result.put("foreigners",c.getString("foreigners")); result.put("nationaTeamPlayers",c.getString("nationaTeamPlayers")); result.put("teamValue",c.getString("teamValue")); result.put("venue",c.getString("venue")); result.put("venueCapacity",c.getString("venueCapacity")); resultList.add(result); } } catch (IOException | JSONException e) { Log.e(TAG, "加载失败: " + e.getMessage()); runOnUiThread(() -> Toast.makeText(getApplicationContext(), "数据加载失败: " + e.getMessage(), Toast.LENGTH_LONG).show()); } return null; }
方案2:删掉多余的AsyncTask,直接用OkHttp异步回调处理
AsyncTask本身在高版本Android已经被废弃,完全没必要多包一层。直接在onCreate里发起OkHttp异步请求,等回调里解析完所有数据,再切到主线程给ListView绑定Adapter即可。
核心逻辑示例:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_team_info); resultList = new ArrayList<>(); lv = findViewById(R.id.list); Toast.makeText(this,"Json Data is downloading",Toast.LENGTH_LONG).show(); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://heisenbug-premier-league-live-scores-v1.p.rapidapi.com/api/premierleague/team?name=Liverpool") .get() .addHeader("X-RapidAPI-Key", "替换成你自己的有效Key") .addHeader("X-RapidAPI-Host", "heisenbug-premier-league-live-scores-v1.p.rapidapi.com") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { runOnUiThread(() -> Toast.makeText(TeamInfo.this, "网络请求失败", Toast.LENGTH_LONG).show()); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { String jsonStr = response.body().string(); Log.e(TAG, "Response from url: " + jsonStr); if (jsonStr != null) { try { JSONObject jsonObj = new JSONObject(jsonStr); JSONArray records = jsonObj.getJSONArray("records"); for (int i = 0; i < records.length(); i++) { JSONObject c = records.getJSONObject(i); HashMap<String, String> result = new HashMap<>(); result.put("league",c.getString("league")); result.put("season",c.getString("season")); result.put("name",c.getString("name")); result.put("officialName",c.getString("officialName")); result.put("address",c.getString("address")); result.put("telephone",c.getString("telephone")); result.put("fax",c.getString("fax")); result.put("website",c.getString("website")); result.put("founded",c.getString("founded")); result.put("teamSize",c.getString("teamSize")); result.put("averageAge",c.getString("averageAge")); result.put("foreigners",c.getString("foreigners")); result.put("nationaTeamPlayers",c.getString("nationaTeamPlayers")); result.put("teamValue",c.getString("teamValue")); result.put("venue",c.getString("venue")); result.put("venueCapacity",c.getString("venueCapacity")); resultList.add(result); } // 切主线程绑定Adapter runOnUiThread(() -> { ListAdapter adapter = new SimpleAdapter(TeamInfo.this, resultList, R.layout.list_item_team, new String[]{ "league","season","name","officialName","address","telephone","fax","website","founded","teamSize","averageAge","foreigners","nationaTeamPlayers","teamValue","venue","venueCapacity"}, new int[]{R.id.league, R.id.season,R.id.name,R.id.officialName,R.id.address,R.id.telephone,R.id.fax,R.id.website,R.id.founded,R.id.teamSize,R.id.averageAge,R.id.foreigners,R.id.nationaTeamPlayers,R.id.teamValue,R.id.venue,R.id.venueCapacity}); lv.setAdapter(adapter); }); } catch (final JSONException e) { Log.e(TAG, "Json parsing error: " + e.getMessage()); runOnUiThread(() -> Toast.makeText(getApplicationContext(), "Json parsing error: " + e.getMessage(), Toast.LENGTH_LONG).show()); } }else { Log.e(TAG, "Couldn't get json from server."); runOnUiThread(() -> Toast.makeText(getApplicationContext(), "Couldn't get json from server. Check LogCat for possible errors!", Toast.LENGTH_LONG).show()); } } }); }
额外检查项
- 确认AndroidManifest.xml里已经加了网络权限:
<uses-permission android:name="android.permission.INTERNET" />,否则高版本系统会直接拦截网络请求 - 所有UI相关操作(弹Toast、绑定Adapter、更新View)必须在主线程执行,OkHttp的回调默认在子线程,必须用
runOnUiThread切换 - 删掉没用的冗余导入,避免不必要的编译警告
内容的提问来源于stack exchange,提问作者Brie
相关产品推荐
相关产品推荐

