You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发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。
  • 修复步骤:
    1. 删除onCreate中多余的adapter.notifyDataSetChanged(),此时数据未加载,调用无意义。
    2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:06:23