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

CustomAdapter的getCount()先返回正数后立即返回0致ListView为空

我帮你找出了几个导致ListView无内容、getCount()异常的核心问题,以及对应的修复方案:

核心问题分析

  1. ArrayAdapter内部数据集与自定义变量不同步
    你继承了ArrayAdapter,但自己维护了一个rows列表,却没和ArrayAdapter内部的数据集同步。ArrayAdapter的getCount()是基于自身内部的mObjects列表计算的,不是你自定义的rows变量——这就是为什么一开始构造函数里能看到100条数据,之后却返回0的原因。

  2. 无效的提前绑定Adapter
    在onCreate里你直接调用了list.setAdapter(customAdapter),但此时customAdapter还是null,这完全是无效操作,还可能干扰后续的Adapter绑定逻辑。

  3. 冗余的数据集重复设置
    在parseHtml里创建完CustomAdapter后,又调用setData(rows)传递同一个列表,不仅多余,还可能导致数据集混乱。


修复方案

1. 修正CustomAdapter,同步数据集

删除自定义的rows变量,直接利用ArrayAdapter的内置方法管理数据,确保getCount()始终返回正确的数据集大小:

package com.example.topsongsbyyear;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import java.util.ArrayList;

public class CustomAdapter extends ArrayAdapter<RowItem> {
    Context context;

    public CustomAdapter(Context context, int resource, ArrayList<RowItem> rows) {
        super(context, resource, rows);
        this.context = context;
        Log.i("--------------", "Adapter初始化,数据条数:" + getCount());
    }

    // 正确的更新数据方法:同步ArrayAdapter内部数据集
    public void setData(ArrayList<RowItem> newRows) {
        clear(); // 清空旧数据
        addAll(newRows); // 添加新数据
        notifyDataSetChanged(); // 通知ListView刷新
        Log.i("--------------", "数据更新完成,当前条数:" + getCount());
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.row_layout, parent, false);
        }

        // 绑定控件
        TextView rank = convertView.findViewById(R.id.rank);
        TextView songName = convertView.findViewById(R.id.song_name);
        TextView artist = convertView.findViewById(R.id.artist);
        ImageView image = convertView.findViewById(R.id.song_image);

        // 获取当前项数据
        RowItem item = getItem(position);
        if (item != null) {
            rank.setText(item.getRank());
            songName.setText(item.getSongName());
            artist.setText(item.getArtist());
            Glide.with(context).load(item.getImageUrl()).into(image);
        }
        return convertView;
    }
}

2. 修正SongList Activity的逻辑

移除无效的提前绑定,优化Adapter的创建与更新逻辑:

package com.example.topsongsbyyear;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;

public class SongList extends AppCompatActivity implements Response.ErrorListener, Response.Listener<String> {
    String webUrl;
    String year;
    RequestQueue requestQueue;
    StringRequest stringRequest;
    ListView list;
    ArrayList<RowItem> rows;
    CustomAdapter customAdapter; // 直接声明为CustomAdapter,方便调用方法

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        year = getIntent().getStringExtra("year");
        webUrl = "https://www.billboard.com/charts/year-end/" + year + "/hot-100-songs";
        setContentView(R.layout.activity_song_list);

        rows = new ArrayList<>();
        list = findViewById(R.id.all_list);

        requestQueue = Volley.newRequestQueue(this);
        stringRequest = new StringRequest(Request.Method.GET, webUrl, this, this);
        requestQueue.add(stringRequest);
        // 不需要调用requestQueue.start(),Volley添加请求后会自动处理
    }

    @Override
    public void onErrorResponse(VolleyError error) {
        Log.i("----------------", "请求失败:" + error.getMessage());
    }

    @Override
    public void onResponse(String response){
        Log.i("----------------", "请求成功,开始解析HTML");
        Document doc = Jsoup.parse(response);
        parseHtml(doc);
    }

    public void parseHtml(Document doc){
        ArrayList<String> songList = new ArrayList<>();
        ArrayList<String> artistList = new ArrayList<>();
        ArrayList<String> imageUrls = new ArrayList<>();
        rows = new ArrayList<>();

        // 解析HTML内容
        Elements songs = doc.select(".ye-chart-item__title");
        for(Element song : songs){
            songList.add(song.text().trim());
        }
        Elements artists = doc.select(".ye-chart-item__artist");
        for(Element artist : artists){
            artistList.add(artist.text().trim());
        }
        Elements images = doc.select("div.ye-chart-item__image > img");
        for (Element image : images) {
            imageUrls.add(image.attr("src"));
        }

        // 填充RowItem列表
        int maxCount = Math.min(Math.min(songList.size(), artistList.size()), imageUrls.size());
        for(int i = 0; i < maxCount; i++){
            rows.add(new RowItem(Integer.toString(i+1), songList.get(i), artistList.get(i), imageUrls.get(i)));
        }

        Log.i("----------------", "解析完成,数据条数:" + rows.size());

        // 更新Adapter:存在则更新数据,不存在则创建并绑定
        if (customAdapter == null) {
            customAdapter = new CustomAdapter(this, R.layout.row_layout, rows);
            list.setAdapter(customAdapter);
        } else {
            customAdapter.setData(rows);
        }
    }
}

额外注意事项

  • 确保RowItem类的getter方法(getRank()、getSongName()等)正确实现,否则getView中无法获取数据。
  • 网页结构可能会变化,要定期检查Jsoup的选择器是否还能匹配目标元素。
  • 可以添加异常处理,避免解析HTML时因列表长度不一致导致崩溃(比如上面代码中用Math.min取最小长度)。

内容的提问来源于stack exchange,提问作者Luke Lewis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:16:23