KaiZ KaiZ - 1 month ago 10
Android Question

Why is my custom ArrayAdapter not getting filled?

The data is coming in fine through Retrofit, and my custom adapter (

NewsAdapter
, based on
ArrayAdapter
) was getting populated before, but I had to make some adjustments to it and I can't get it working at all now.

The idea is to get each news source available, get the articles for each specific news source, and then populate my GridView with those articles. The
articles
member on
NewsAdapter
gets filled, but not the adapter itself, from what I understand.
Here is my code, and console output that I made for checking the values:

Console output:

I/System.out: Source ID: nfl-news
I/System.out: Adapter count: 0
I/System.out: Response body: [pt.ismai.a26800.readr.Articles_Map@ca5fafc, pt.ismai.a26800.readr.Articles_Map@cd585, pt.ismai.a26800.readr.Articles_Map@8639fda, pt.ismai.a26800.readr.Articles_Map@9bbac0b, pt.ismai.a26800.readr.Articles_Map@ed5cae8, pt.ismai.a26800.readr.Articles_Map@c4a4501, pt.ismai.a26800.readr.Articles_Map@c6bdfa6, pt.ismai.a26800.readr.Articles_Map@876fde7, pt.ismai.a26800.readr.Articles_Map@3b0ad94, pt.ismai.a26800.readr.Articles_Map@b95303d]
I/System.out: Articles count: 10
I/System.out: Source ID: espn-cric-info
I/System.out: Adapter count: 0
I/System.out: Response body: [pt.ismai.a26800.readr.Articles_Map@f665032, pt.ismai.a26800.readr.Articles_Map@3ab9183, pt.ismai.a26800.readr.Articles_Map@4b50f00, pt.ismai.a26800.readr.Articles_Map@5a99339, pt.ismai.a26800.readr.Articles_Map@b253d7e, pt.ismai.a26800.readr.Articles_Map@50bc2df, pt.ismai.a26800.readr.Articles_Map@2dc1b2c]
I/System.out: Articles count: 17
I/System.out: Source ID: fox-sports
I/System.out: Adapter count: 0
I/System.out: Response body: [pt.ismai.a26800.readr.Articles_Map@80729f5, pt.ismai.a26800.readr.Articles_Map@253b38a, pt.ismai.a26800.readr.Articles_Map@513adfb, pt.ismai.a26800.readr.Articles_Map@385be18, pt.ismai.a26800.readr.Articles_Map@e6d7071]
I/System.out: Articles count: 22


ListNewsActivity:

public class ListNewsActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
/* ... */

// parameters for Sources endpoint
String category = "sport";
String language = "en";
String country = "us";

// Sources endpoint
Sources_Interface client_sources = NewsAPI_Adapter.createService(Sources_Interface.class);
Call<Sources_Map> call_sources = client_sources.getData(category, language, country);

call_sources.enqueue(new Callback<Sources_Map>() {
@Override
public void onResponse(Call<Sources_Map> call_sources, Response<Sources_Map> response) {
if (response.body() != null) {
final NewsAdapter nAdapter = new NewsAdapter(ListNewsActivity.this,
R.layout.article_layout);

for (final Sources_Content source : response.body().sources) {
if (source.sortBysAvailable.contains("latest")) {

// Articles endpoint
NewsAPI_Interface client = NewsAPI_Adapter.createService(NewsAPI_Interface.class);
Call<NewsAPI_Map> call = client.getData(source.id, "apiKeyHere");

call.enqueue(new Callback<NewsAPI_Map>() {
@Override
public void onResponse(Call<NewsAPI_Map> call, Response<NewsAPI_Map> response) {
if (response.body() != null) {
ExpandableHeightGridView gv_content = (ExpandableHeightGridView) findViewById(R.id.gv_content);
nAdapter.addAll(response.body().articles);
System.out.println("Source ID: " + source.id + "\n" +
"Adapter count: " + nAdapter.getCount() + "\n" +
"Response body: " + response.body().articles + "\n" +
"Articles count: " + nAdapter.articles.size() + "\n");
gv_content.setAdapter(nAdapter);
gv_content.setExpanded(true);
}
}

@Override
public void onFailure(Call<NewsAPI_Map> call, Throwable t) {
System.out.println("An error ocurred!\n" +
"URL: " + call.request().url() + "\n" +
"Cause: " + t.getCause().toString());
}
});
}
}
}
}

@Override
public void onFailure(Call<Sources_Map> call_sources, Throwable t) {
System.out.println("An error ocurred!");
}
});
}
}


NewsAdapter:

public class NewsAdapter extends ArrayAdapter<Articles_Map> {
Context mContext;
List<Articles_Map> articles;

public NewsAdapter(Context c, int resource) {
super(c, resource);
this.mContext = c;
this.articles = new ArrayList<>();
}

public NewsAdapter(Context c, int resource, List<Articles_Map> articles) {
super(c, resource, articles);
this.mContext = c;
this.articles = articles;
}

public void addAll(List<Articles_Map> articles) {
if (this.articles == null) {
this.articles = new ArrayList<>(articles);
} else {
this.articles.addAll(articles);
}
notifyDataSetChanged();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// get the property we are displaying
Articles_Map article = articles.get(position);

// get the inflater and inflate the XML layout for each item
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.article_layout, null);

ImageView thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
TextView title = (TextView) view.findViewById(R.id.title);
TextView description = (TextView) view.findViewById(R.id.description);

Picasso.with(mContext).load(article.urlToImage).into(thumbnail);
title.setText(article.title);
description.setText(article.description);

return view;
}
}


NewsAPI_Map:

public class NewsAPI_Map {
String status;
String source;
List<Articles_Map> articles;

public NewsAPI_Map(String status, String source, List<Articles_Map> articles) {
this.status = status;
this.source = source;
this.articles = articles;
}
}


Articles_Map:

public class Articles_Map {
String title;
String description;
String url;
String urlToImage;

public Articles_Map(String title, String description, String url, String urlToImage) {
this.title = title;
this.description = description;
this.url = url;
this.urlToImage = urlToImage;
}
}

Answer

Something about getCount is returning 0, and so the adapter thinks it shouldn't be displaying data into the list. I believe this is because you called the constructor which does not initialize the underlying List.

You shouldn't need to define your own List within your adapter implementation. The ArrayAdapter super class has one.

So, remove those references. (You also don't really need the Context since getContext() is available).

public class NewsAdapter extends ArrayAdapter<Articles_Map> {
    Context mContext;

    public NewsAdapter(Context c, int resource) {
        super(c, resource);
        this.mContext = c;
    }

    public NewsAdapter(Context c, int resource, List<Articles_Map> articles) {
        super(c, resource, articles);
        this.mContext = c;
    }

Then, in getView, use getItem(position) instead.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // get the property we are displaying
    Articles_Map article = getItem(position);

And you can still use adapter.add or adapter.addAll, which does add to the underlying List and notifies the dataset.

Comments