简体   繁体   中英

Why does my app crash with a NullPointerException, and why is my adapter (probably) null?

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)
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.

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 eg

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM