简体   繁体   中英

java.lang.NullPointerException with RecyclerView and CardView

I am trying to make dynamical list using RecyclerView and CardView using tutorial from this site and I am getting this error:

java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
        at kawi15.myapplication.CustomAdapter.getItemCount(CustomAdapter.java:66) 

I run debugger to check that I have results from tmbd API and this is what I received: http://prntscr.com/vdjj1h

This is my Fragment class activity when I want to create that list:


public class FragmentOne extends Fragment {

    private static RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;
    private static RecyclerView recyclerView;
    private static List<MovieDb> data;
    static View.OnClickListener myOnClickListener;

    public static FragmentOne newInstance() {
        FragmentOne fragment = new FragmentOne();
        return fragment;
    }

    public class MovieTask extends AsyncTask<Void, Void, List<MovieDb>> {
        @Override
        protected List<MovieDb> doInBackground(Void... voids) {
            MovieResultsPage movies = new TmdbApi("f753872c7aa5c000e0f46a4ea6fc49b2").getMovies().getUpcoming("en-US", 1, "US");
            List<MovieDb> listMovies = movies.getResults();

            return listMovies;
        }

        @Override
        protected void onPostExecute(List<MovieDb> movieDb) {
            data = movieDb;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        MovieTask mt = new MovieTask();
        mt.execute();
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View returnView = inflater.inflate(R.layout.fragment_one, container, false);
        recyclerView = (RecyclerView) returnView.findViewById(R.id.my_recycler_view);
        recyclerView.setHasFixedSize(true);

        layoutManager = new LinearLayoutManager(getContext());  // ???
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());



        adapter = new CustomAdapter(data);
        recyclerView.setAdapter(adapter);



        return returnView;
    }
}

and my Adapter class:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {

    private List<MovieDb> dataSet;

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        TextView textViewName;
        TextView textViewVersion;
        ImageView imageViewIcon;

        public MyViewHolder(View itemView) {
            super(itemView);
            this.textViewName = (TextView) itemView.findViewById(R.id.text1);
            this.textViewVersion = (TextView) itemView.findViewById(R.id.text2);
            this.imageViewIcon = (ImageView) itemView.findViewById(R.id.imageView);
        }
    }

    public CustomAdapter(List<MovieDb> data) {
        this.dataSet = data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent,
                                           int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cards_layout, parent, false);

        //view.setOnClickListener(MainActivity.myOnClickListener);

        MyViewHolder myViewHolder = new MyViewHolder(view);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {

        TextView textViewName = holder.textViewName;
        TextView textViewVersion = holder.textViewVersion;
        ImageView imageView = holder.imageViewIcon;
        Glide.with(imageView).load("http://image.tmdb.org/t/p/w500" + dataSet.get(listPosition).getPosterPath()).into(imageView);

        textViewName.setText(dataSet.get(listPosition).getOriginalTitle());
        textViewVersion.setText(dataSet.get(listPosition).getReleaseDate());
        //imageView.setImageResource(dataSet.get(listPosition).);
    }

    @Override
    public int getItemCount() {
        return dataSet.size();
    }
}

I stucked with my code with this and I dont have idea where is mistake.

Initially dataSet is null . So using dataSet.size() is throwing NullPointerException. Change getItemCount method in the following way.

 @Override
 public int getItemCount() {
     if(dataSet == null){
          return 0;
     }
     return dataSet.size();
 }

This is removing error but its still doesnt work because data is null making dataSet null too. I dont know why data is null, I need help with this.

Reason for that could be, you are creating CustomAdapter object in onCreateView method, which is kind of called before you AsyncTask has finished. So, when onCreateView is being called, data is null.

To fix it, You can add a setter method in your CustomAdapter , which will allow you to update dataSet , even after the adapter object is created. Then you will have to update the dataSet in your onPostExecute method & after that use notifyDataSetChanged on the adapter, to reflect the changes.

At the start dataSet will be null until you assign it a value, and then feed it back with data, so change getItemCount() to below to return 0 data when it's null

@Override
public int getItemCount() {
    return dataSet == null ? 0 : dataSet.size();
}

Ok, there is no error and application is launching but still I dont have list and this is my problem

You need to update the changes to your adapter with notifyDataSetChanged()

    @Override
    protected void onPostExecute(List<MovieDb> movieDb) {
        data = movieDb;
        adapter.notifyDataSetChanged();
    }

Now two possible things, either TmdbApi("...").getMovies() doesn't really return data, in this case you need to debug it and check if it returns data or not.

The other thing, move the code of the AsyncTask execution after creating the RecyclerView instance in onCreateView and Initialize the adapter in onPostExecute() ;

Here are after the changes:

public class MovieTask extends AsyncTask<Void, Void, List<MovieDb>> {
    @Override
    protected List<MovieDb> doInBackground(Void... voids) {
        MovieResultsPage movies = new TmdbApi("f753872c7aa5c000e0f46a4ea6fc49b2").getMovies().getUpcoming("en-US", 1, "US");
        List<MovieDb> listMovies = movies.getResults();

        return listMovies;
    }

    @Override
    protected void onPostExecute(List<MovieDb> movieDb) {

        data = movieDb;
        adapter = new CustomAdapter(data);
        recyclerView.setAdapter(adapter);
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View returnView = inflater.inflate(R.layout.fragment_one, container, false);
 

    recyclerView = (RecyclerView) returnView.findViewById(R.id.my_recycler_view);
    recyclerView.setHasFixedSize(true);

    layoutManager = new LinearLayoutManager(getContext());  // ???
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());

    MovieTask mt = new MovieTask();
    mt.execute();

    return returnView;
}

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