简体   繁体   English

为什么我的应用程序会因 NullPointerException 而崩溃,为什么我的适配器(可能)为空?

[英]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.数据通过 Retrofit 输入良好,并且我的自定义适配器( NewsAdapter ,基于 ArrayAdapter )之前已填充,但我必须对其进行一些调整,现在我根本无法使其正常工作。

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.这个想法是让每个新闻源可用,获取每个特定新闻源的文章,然后用这些文章填充我的 GridView。 Here is my code:这是我的代码:

NewsAdapter : 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 : 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 : 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 : 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:记得在使用前检查null:

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 类中,您忘记为您的对象放置 getter 和 setter。

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.由于您的类 getter 和 setter,您的其余 API 可能无法将数据转换为您的对象。

You are basically using the first constructor which means you need to pass your ArrayList<Articles_Map> .您基本上使用的是第一个构造函数,这意味着您需要传递ArrayList<Articles_Map> Using your first constructor makes your Array uninitialized and that's causing your the Nullpointer Exception .使用您的第一个构造函数会使您的 Array 未初始化,这会导致您的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您需要通过提供ArrayList<Articles_Map>实例来使用其他重载的构造函数,例如

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.我添加了代码add(Articles_Map m)以便您可以在回调中使用它,在这种情况下您不需要重新初始化您的适配器。

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);要解决此问题,请进入您在此处定义的 addAll() 方法 nAdapter.addAll(response.body().articles);

and add at the beginning of your method if(articles == null){ articles = new ArrayList articles();并在方法的开头添加 if(articles == null){articles = new ArrayList articles(); } }

and after that don't forget to call .notifyDataHasChanged();之后不要忘记调用 .notifyDataHasChanged();

that's a basic programming rule you should know though as Collections are not an android-thing这是您应该知道的基本编程规则,因为 Collections 不是 android 的东西

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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