Android CustomAdapter getCount()首先返回正计数,然后立即返回0

Android CustomAdapter getCount()首先返回正计数,然后立即返回0,android,android-adapter,custom-adapter,Android,Android Adapter,Custom Adapter,我制作了一个自定义适配器,以便可以制作自定义列表视图。自定义适配器接收我自己的RowItem类的ArrayList,并在我的活动中填充我的列表视图 当我尝试使用自定义适配器时,活动中没有出现任何问题。经过一些研究,我怀疑可能是适配器的getCount函数返回了一个0,所以我添加了一些日志信息来检查它 它显示的是,一开始,我的getCount确实返回一个正值(100),但接下来,它返回一个零,并继续这样做,这意味着我的getView没有被调用,列表仍然为空 这是我的活动 package com.e

我制作了一个自定义适配器,以便可以制作自定义列表视图。自定义适配器接收我自己的RowItem类的ArrayList,并在我的活动中填充我的列表视图

当我尝试使用自定义适配器时,活动中没有出现任何问题。经过一些研究,我怀疑可能是适配器的getCount函数返回了一个0,所以我添加了一些日志信息来检查它

它显示的是,一开始,我的getCount确实返回一个正值(100),但接下来,它返回一个零,并继续这样做,这意味着我的getView没有被调用,列表仍然为空

这是我的活动

package com.example.topsongsbyyear;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListAdapter;
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;
    RowItem row;
    ListView list;
    ArrayList<RowItem> rows;
    ListAdapter 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<RowItem>();
        list = (ListView) findViewById(R.id.all_list);
        list.setAdapter(customAdapter);
        requestQueue = Volley.newRequestQueue(this);
        stringRequest = new StringRequest(Request.Method.GET, webUrl, this, this);
        requestQueue.add(stringRequest);
        requestQueue.start();
    }

    @Override
    public void onErrorResponse(VolleyError error) {
        Log.i("----------------", "onErrorResponse executed");
    }

    @Override
    public void onResponse(String response){
        int rank = 1;
        Log.i("----------------", "onResponse executed");
        Document doc = Jsoup.parse(response);
        parseHtml(doc);
        //call setData function in adapter
        //in setData, save the data and call notifyDataSetChanged (adapter method), which updates list view
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }

    public void parseHtml(Document doc){
        ArrayList<String> songList = new ArrayList<>();
        ArrayList<String> artistList = new ArrayList<>();
        ArrayList<String> imageUrls = new ArrayList<>();
        rows = new ArrayList<RowItem>();
        Elements songs = doc.select(".ye-chart-item__title");
        for(Element song : songs){
            songList.add(song.text().toString());
        }
        Elements artists = doc.select(".ye-chart-item__artist");
        for(Element artist : artists){
            artistList.add(artist.text().toString());
        }
        Elements images = doc.select("div.ye-chart-item__image > img");
        for (Element image : images) {
            imageUrls.add(image.attr("src"));
        }
        for(int i = 0; i < songList.size(); i++){
            RowItem row = new RowItem(Integer.toString(i+1), songList.get(i), artistList.get(i), imageUrls.get(i));
            rows.add(row);
        }
        Log.i("----------------", "Just added to rows arrayList with songList size: " + songList.size() + " artistList size: " + artistList.size() + "and imageUrls size: " +imageUrls.size());
        Log.i("----------------", "Just before setting making customAdapter instance with row count " + rows.size());
        customAdapter = new CustomAdapter(this, R.layout.row_layout, rows);
        list.setAdapter(customAdapter);
        if (customAdapter instanceof CustomAdapter){
            ((CustomAdapter) customAdapter).setData(rows);
        }
        Log.i("----------------","Adapter set after html parsed, with row count " + rows.size());




    }
}
此外,如果我的setData函数没有在任何地方调用(在我的parseHtml或自定义适配器构造函数中),我的应用程序就会崩溃


有人知道我做错了什么吗?谢谢。

尝试设置此选项。行=行;在setData方法中,您将随时更新它


请注意,您只是在CustomAdapter的构造函数中设置this.rows,而在设置数据时,您并没有设置它。另外,调用clear();在setData中,正在清除this.rows列表,因为数组适配器在构造函数中持有对要通过super的列表的引用。

ArrayAdapter
为其数据集维护一个私有的
列表
字段。当您在
super
构造函数调用中传递
rows
时,它的字段然后指向您的
ArrayList
,即100项。到目前为止,一切顺利。但是,然后调用
setData()
方法,该方法调用
clear()ArrayAdapter
上的code>,它清除其
列表
字段,但该字段指向您的
列表
,因此它会被清除,随后的
addAll()
调用只会将一个空的
列表
添加到一个空的
列表
,因此返回0。也许最简单的解决方案就是去掉
ArrayList行字段。。。。。。并让
ArrayAdapter
处理
列表
。您可以使用
ArrayAdapter
getItem()
方法代替所有的
行.get()
调用,只需删除
getCount()
覆盖,因为
ArrayAdapter
将正确处理它。或者,扩展
BaseAdapter
,这样你是唯一一个接触
列表的人,并且确切地知道在哪里发生了什么。嘿,迈克,我听从了你的建议,摆脱了我的ArrayList,改为使用ArrayAdapter的getItem()方法,效果很好!我也不需要setData()方法,只需在构造函数中调用notifyDataSetChanged()。非常感谢你的帮助!嗨,马克。多亏了Mike M.的投入,我已经解决了这个问题。不过我还是很感激你的帮助!非常感谢。
package com.example.topsongsbyyear;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.util.Log;
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;
    ArrayList<RowItem> rows;
    TextView songName;
    TextView artist;
    TextView rank;
    ImageView image;

    public CustomAdapter(@NonNull Context context, int resource, ArrayList<RowItem> rows) {
        super(context, resource, rows);
        this.rows = rows;
        Log.i("--------------", "row filled with " + this.rows.size() + " elements");
        notifyDataSetChanged();
        //setData(rows);
    }

    public void setData(ArrayList<RowItem> rows){
        clear();
        addAll(rows);
        Log.i("----------------", "setData called, cleared and then addAll(rows) with row count: " + rows.size());
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        Log.i("----------------", "CustomAdapter getCount called, returning rows.size() which is: " + rows.size());
        return rows.size();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Log.i("---------------", "entered getView function");
        LayoutInflater inflater = LayoutInflater.from(getContext());
        View customView = convertView;
        if (convertView == null)
            customView = inflater.inflate(R.layout.row_layout, parent, false);

        //setData(rows);
        String singleSong = rows.get(position).getSong();
        String singleArtist = rows.get(position).getArtist();
        String singleRank = rows.get(position).getRank();
        String singleImage = rows.get(position).getPicUrl();
        songName = (TextView) customView.findViewById(R.id.title);
        artist = (TextView) customView.findViewById(R.id.artist);
        rank = (TextView) customView.findViewById(R.id.rank);
        Log.i("----------------", "ADDED: " + singleRank + " " + singleSong + " by " + singleArtist +" TO LIST");
        image = (ImageView) customView.findViewById(R.id.list_image);

        songName.setText(singleSong);
        artist.setText(singleArtist);
        rank.setText(singleRank);

        Glide.with(context).
                load(singleImage).
                into(image);

        return customView;
    }

}
05-10 19:49:54.610 29217-29217/com.example.topsongsbyyear I/----------------: onResponse executed
05-10 19:49:54.657 29217-29217/com.example.topsongsbyyear I/----------------: Just added to rows arrayList with songList size: 100 artistList size: 100and imageUrls size: 100
05-10 19:49:54.658 29217-29217/com.example.topsongsbyyear I/----------------: Just before setting making customAdapter instance with row count 100
05-10 19:49:54.658 29217-29217/com.example.topsongsbyyear I/--------------: row filled with 100 elements
05-10 19:49:54.658 29217-29217/com.example.topsongsbyyear I/----------------: CustomAdapter getCount called, returning rows.size() which is: 100
    CustomAdapter getCount called, returning rows.size() which is: 100
05-10 19:49:54.659 29217-29217/com.example.topsongsbyyear I/----------------: CustomAdapter getCount called, returning rows.size() which is: 0
05-10 19:49:54.659 29217-29217/com.example.topsongsbyyear I/chatty: uid=10086(com.example.topsongsbyyear) identical 2 lines
05-10 19:49:54.660 29217-29217/com.example.topsongsbyyear I/----------------: CustomAdapter getCount called, returning rows.size() which is: 0
    setData called, cleared and then addAll(rows) with row count: 0
    CustomAdapter getCount called, returning rows.size() which is: 0
    CustomAdapter getCount called, returning rows.size() which is: 0
    Adapter set after html parsed, with row count 0
05-10 19:49:54.675 29217-29217/com.example.topsongsbyyear I/----------------: CustomAdapter getCount called, returning rows.size() which is: 0
05-10 19:49:54.681 29217-29217/com.example.topsongsbyyear I/----------------: CustomAdapter getCount called, returning rows.size() which is: 0
05-10 19:49:54.842 29217-29217/com.example.topsongsbyyear I/----------------: CustomAdapter getCount called, returning rows.size() which is: 0
05-10 19:49:54.844 29217-29217/com.example.topsongsbyyear I/----------------: CustomAdapter getCount called, returning rows.size() which is: 0
05-10 19:49:55.057 29217-29241/com.example.topsongsbyyear I/chatty: uid=10086(com.example.topsongsbyyear) RenderThread identical 2 lines