开发Hacker News阅读器:无法在ListView显示ArrayList内容求助
问题:ListView无法显示Hacker News新闻标题
我正在基于Hacker News API开发一款基础新闻阅读器应用,已成功获取新闻标题和URL并将其以字符串形式存入对应的ArrayList,但无法在ListView中显示标题。后续计划添加WebView,但当前ListView的显示问题阻碍了开发,不清楚问题出在哪里。
相关代码
public class MainActivity extends AppCompatActivity { ListView listView; ArrayList<String> titles; ArrayList<String> siteUrls; ArrayAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); titles = new ArrayList<>(); siteUrls = new ArrayList<>(); listView = (ListView) findViewById(R.id.view); DownloadAsyncTask download = new DownloadAsyncTask(); download.execute("https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty"); adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, titles); listView.setAdapter(adapter); adapter.notifyDataSetChanged(); } public class DownloadAsyncTask extends AsyncTask<String, Void, String>{ JSONArray codes; URL url; HttpURLConnection connection; InputStream stream; InputStreamReader reader; @Override protected String doInBackground(String... urls) { try { url = new URL(urls[0]); connection = (HttpURLConnection) url.openConnection(); stream = connection.getInputStream(); reader = new InputStreamReader(stream); int data = reader.read(); String feed = ""; while(data != -1) { char character = (char) data; feed += character; data = reader.read(); } Log.i("feed: ", feed); codes = new JSONArray(feed); Log.i("Length: ", String.valueOf(codes.length())); for(int i = 0; i < 20; i++){ String id = codes.getString(i); Log.i("id: ", id); url = new URL("https://hacker-news.firebaseio.com/v0/item/" + id +".json?print=pretty"); connection = (HttpURLConnection) url.openConnection(); stream = connection.getInputStream(); reader = new InputStreamReader(stream); int data1 = reader.read(); String jsonFeed = ""; while(data1 != -1){ char c = (char) data1; jsonFeed += c; data1 = reader.read(); } JSONObject part = new JSONObject(jsonFeed); if(!part.isNull("title") && !part.isNull("url")) { titles.add(part.getString("title")); siteUrls.add(part.getString("url")); } } } catch (Exception e) { e.printStackTrace(); } return ""; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); } } }
问题原因与修复方案
- 核心问题:
onCreate中调用adapter.notifyDataSetChanged()时,后台网络请求还未完成,titles列表为空;而当后台请求结束、titles被填充后,没有通知适配器更新UI。 - 修复步骤:
- 删除
onCreate中多余的adapter.notifyDataSetChanged(),此时数据未加载,调用无意义。 - 在
DownloadAsyncTask的onPostExecute方法中添加adapter.notifyDataSetChanged(),该方法运行在主线程,是后台任务完成后更新UI的正确时机。
- 删除
修改后的关键代码片段:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); titles = new ArrayList<>(); siteUrls = new ArrayList<>(); listView = (ListView) findViewById(R.id.view); DownloadAsyncTask download = new DownloadAsyncTask(); download.execute("https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty"); adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, titles); listView.setAdapter(adapter); // 移除此处的notifyDataSetChanged() } // ... @Override protected void onPostExecute(String s) { super.onPostExecute(s); // 后台任务完成后通知适配器刷新UI adapter.notifyDataSetChanged(); }
额外优化建议
- 网络请求中创建的
HttpURLConnection、InputStream等资源,使用后需调用close()方法释放,避免内存泄漏。 - 用
BufferedReader替代逐个字符读取的方式,提升数据读取效率,示例:BufferedReader bufferedReader = new BufferedReader(reader); String line; StringBuilder feed = new StringBuilder(); while ((line = bufferedReader.readLine()) != null) { feed.append(line); } - 考虑使用Retrofit等现代网络库替代原生
HttpURLConnection,简化网络请求代码,同时提升稳定性和可维护性。
内容的提问来源于stack exchange,提问作者Cliff Ki
相关产品推荐
相关产品推荐

