-2

When my app tries to get the position on the adapter, it crashes, because apparently my adapter isn't getting populated correctly.

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. Here is my code:

NewsAdapter:

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

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

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

    @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;
    ArrayList<Articles_Map> articles;

    public NewsAPI_Map(String status, String source, ArrayList<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;
    }
}

ListNewsActivity.java:

@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 (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("Count: " + nAdapter.getCount() + "\n" +
                                            "Body: " + response.body().articles + "\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!");
        }
    });
}

Logs:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: pt.ismai.a26800.readr, PID: 8398
                  java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.util.ArrayList.get(int)' on a null object reference
                      at pt.ismai.a26800.readr.NewsAdapter.getView(NewsAdapter.java:38)
                      at android.widget.AbsListView.obtainView(AbsListView.java:2346)
                      at android.widget.GridView.onMeasure(GridView.java:1065)
                      at pt.ismai.a26800.readr.ExpandableHeightGridView.onMeasure(ExpandableHeightGridView.java:37)
                      at android.view.View.measure(View.java:18804)
                      at android.support.v4.widget.NestedScrollView.measureChildWithMargins(NestedScrollView.java:1411)
                      at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                      at android.support.v4.widget.NestedScrollView.onMeasure(NestedScrollView.java:479)
                      at android.view.View.measure(View.java:18804)
                      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
                      at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:700)
                      at android.support.design.widget.HeaderScrollingViewBehavior.onMeasureChild(HeaderScrollingViewBehavior.java:90)
                      at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onMeasureChild(AppBarLayout.java:1364)
                      at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:765)
                      at android.view.View.measure(View.java:18804)
                      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
                      at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                      at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
                      at android.view.View.measure(View.java:18804)
                      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
                      at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
                      at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
                      at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
                      at android.view.View.measure(View.java:18804)
                      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
                      at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                      at android.view.View.measure(View.java:18804)
                      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
                      at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
                      at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
                      at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
                      at android.view.View.measure(View.java:18804)
                      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
                      at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                      at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
                      at android.view.View.measure(View.java:18804)
                      at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2112)
                      at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1228)
                      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1464)
                      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1119)
                      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6060)
                      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
                      at android.view.Choreographer.doCallbacks(Choreographer.java:670)
                      at android.view.Choreographer.doFrame(Choreographer.java:606)
                      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
                      at android.os.Handler.handleCallback(Handler.java:746)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:148)
                      at android.app.ActivityThread.main(ActivityThread.java:5443)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
KaiZ
  • 391
  • 1
  • 5
  • 13
  • Post the logs please. – Enzokie Oct 17 '16 at 00:39
  • @Enzokie I'm new to Android development, but I'm assuming that by logs you meant console output, so I've added that to my original post. In case you meant you something else, just ask. – KaiZ Oct 17 '16 at 00:55

3 Answers3

1
Articles_Map article = articles.get(position);

Remember to check null before use:

if (articles != null)
{
    Articles_Map article = articles.get(position);
    //other code
}

On your NewsAPI_Map class, you forget to put getter & setter for your object.

NewsAPI_Map:

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

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

    public void setStatus(String status){
        this.status = status;
    }

    public String getStatus(){
        return this.status;
    }
    ....
}

May your rest API cannot convert data to your object because of your class getter & setter.

PLe
  • 137
  • 4
0

You are basically using the first constructor which means you need to pass your ArrayList<Articles_Map>. Using your first constructor makes your Array uninitialized and that's causing your the Nullpointer Exception.

final NewsAdapter nAdapter = new NewsAdapter(ListNewsActivity.this,
                        R.layout.article_layout);

While your requirements is the second one.

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

You need to use the other overloaded constructor by supplying the ArrayList<Articles_Map> instance e.g.

final NewsAdapter nAdapter = new NewsAdapter(ListNewsActivity.this,
                            R.layout.article_layout, articles);

Update Code

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

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

    public void add(Articles_Map m){
       articles.add(m);
       notifyDataSetChanged();
    }

    ... more code ...
}

I added the code add(Articles_Map m) so that you can use it in your callback, in this case you do not need to reinitialize your Adapter.

Enzokie
  • 7,365
  • 6
  • 33
  • 39
  • Yes I know, and that constructor is the one I was using before my changes, and everything was working correctly. However, as far as I understand, I can't use that same constructor currently, because if I declare the variable and use that 3 argument constructor inside onResponse(), it'll keep getting declared for that same variable since it is inside a loop, which is a problem. And I can't see how to get around that. – KaiZ Oct 17 '16 at 01:13
  • Actually you should declare your Adapter as Member variable, what you need to here is a method that accepts `Articles_Map` argument then 'invalidate' the view. – Enzokie Oct 17 '16 at 01:22
  • I'm sorry, but I didn't quite understand what you meant... Can you clarify what you mean by "a method that accepts Articles_Map argument then 'invalidate' the view."? – KaiZ Oct 17 '16 at 02:04
  • @KaiZ see my update, it should give you an idea on how to use it. – Enzokie Oct 17 '16 at 02:18
0

the problem is that you're creating your Adapter using the first Constructor, which doesn't initialize the dataset( your array list ) so it is null. Then you try to add data to your dataset "articles", which won't work as it's not initialized.

To solve this, go into your addAll() method you had defined here nAdapter.addAll(response.body().articles);

and add at the beginning of your method if(articles == null){ articles = new ArrayList articles(); }

and after that don't forget to call .notifyDataHasChanged();

that's a basic programming rule you should know though as Collections are not an android-thing

Makaveli
  • 101
  • 10
  • I actually hadn't defined an addAll() method before, but I made one just now anyway. I coded it like [this](https://gist.github.com/KaiZ51/a3f7b1abcdfcb9acad3fe3f2ca9d346f), I'm not sure if that's right. The app doesn't crash now, but it doesn't seem to be filling up the adapter, as nothing shows and my getCount() is at 0 always. – KaiZ Oct 17 '16 at 02:02
  • http://stackoverflow.com/a/5092426/3325970 this should answer your problem – Makaveli Oct 17 '16 at 02:29