3

I'm very new at Android/Java development, although I'm an experienced web dev. I've read this and this, and am still having problems.

I have a SQLite database with a table called Restaurants, that stores, well, restaurants. I'm trying to use a RecyclerView to display a list of restaurants.

I'm getting a null pointer exception, and can't seem to figure out what is null.

Here's my RecyclerView class:

package com.myapp.lunchboxchicago.adapters;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.myapp.lunchboxchicago.Message;
import com.myapp.lunchboxchicago.R;
import com.myapp.lunchboxchicago.restaurants.Restaurant;

/**
 * Created by estrom on 3/23/2016.
 */
public class RestaurantViewAdapter extends RecyclerView.Adapter<RestaurantViewAdapter.RestaurantViewHolder> {
    public static final String TAG = RestaurantViewAdapter.class.getSimpleName();
    private Restaurant[] mRestaurants;
    private Context mContext;

    public RestaurantViewAdapter(Context context, Restaurant[] restaurants) {
        mContext = context;
        mRestaurants = restaurants;
    }

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

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(RestaurantViewHolder holder, int position) {
        holder.bindRestaurant(mRestaurants[position]);
    }

    @Override
    public int getItemCount() {
        return mRestaurants.length;
    }

    public class RestaurantViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView mRestaurantName;

        public RestaurantViewHolder(View itemView) {
            super(itemView);
            mRestaurantName = (TextView) itemView.findViewById(R.id.restaurantNameLabel);
            itemView.setOnClickListener(this);
        }

        public void bindRestaurant(Restaurant restaurant) {
            Log.wtf(TAG, "Binding " + restaurant.getName());
            Log.wtf(TAG, "To TextView ID: " + mRestaurantName.getId());
            mRestaurantName.setText(restaurant.getName());
        }

        @Override
        public void onClick(View v) {
            Message.message(mContext, "We'd open " + mRestaurantName + " in the view screen");
        }
    }
}

The two Log statements in bindRestaurant return the following:

03-26 19:17:34.033 30414-30414/com.myapp.lunchboxchicago E/RestaurantViewAdapter: Binding Shamrock Club
03-26 19:17:34.050 30414-30414/com.myapp.lunchboxchicago E/RestaurantViewAdapter: To TextView ID: 2131558502

So it looks like both objects required exist and are instantiated. But I'm still getting this error on the very next line (mRestaurantName.setText(restaurant.getName());)

03-26 19:17:34.057 30414-30414/com.myapp.lunchboxchicago D/AndroidRuntime: Shutting down VM
03-26 19:17:34.058 30414-30414/com.myapp.lunchboxchicago E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                  Process: com.myapp.lunchboxchicago, PID: 30414
                                                                                  java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.myapp.lunchboxchicago.restaurants.Restaurant.getName()' on a null object reference
                                                                                      at com.myapp.lunchboxchicago.adapters.RestaurantViewAdapter$RestaurantViewHolder.bindRestaurant(RestaurantViewAdapter.java:62)
                                                                                      at com.myapp.lunchboxchicago.adapters.RestaurantViewAdapter.onBindViewHolder(RestaurantViewAdapter.java:44)
                                                                                      at com.myapp.lunchboxchicago.adapters.RestaurantViewAdapter.onBindViewHolder(RestaurantViewAdapter.java:18)

I'm confused. What object am I missing that is null here?

Community
  • 1
  • 1
EmmyS
  • 11,892
  • 48
  • 101
  • 156

1 Answers1

0

The restaurant parameter to bindRestaurant is null. It would appear that the restaurant array passed in to the constructor has the possibility of nullable elements, if it's even been initialized correctly.

Allocating the array just creates a holder for the object reference, you still have to actually put something into each position of the array, so either the array is all nulls or specific positions are.

Scott Sosna
  • 1,443
  • 1
  • 8
  • 8
  • But the log messages printed correctly... – Farbod Salamat-Zadeh Mar 27 '16 at 00:45
  • No this is totally wrong. The log output proves that that element in the array is not null. The first call to `restaurant.getName()` works perfectly and the second call does not work. – Luke Cauthen Mar 27 '16 at 00:46
  • the stack trace shows that the method where the NPE occurs is bindRestaurant and that the method failing is Restaurant.getName(), so while I can't determine which of the two, I would expect both to fail. – Scott Sosna Mar 27 '16 at 00:55
  • Even if it's a multithreaded program, the reference passed into the method should remain unchanged even if the array is updated out from under you. And garbage collection isn't going to get in the way either. – Scott Sosna Mar 27 '16 at 00:56
  • But it is obvious that both don't fail because of the log statement `Binding Shamrock Club` – Luke Cauthen Mar 27 '16 at 00:57
  • 3
    then use your debugger and walk it step-by-step through the method, because what you're saying doesn't jive reviewing the code – Scott Sosna Mar 27 '16 at 01:03
  • Nope. As the others have said, if the restaurant parameter was null, the log line that references it wouldn't have worked. Somehow, it's dying in between the log line and the one immediately after it, and I can't for the life of me figure out why. – EmmyS Mar 27 '16 at 03:59
  • I've tried using the debugger. I put a breakpoint on the `bindRestaurant` function and stepped through. It runs through the first restaurant with no problem. The second time through, it just stops - doesn't throw an error, and up until it stops, all watches and variables are as expected. That isn't exactly helpful. Here's a [video](https://drive.google.com/file/d/0B58EPWwXYv6GYUxnX1JnVWNDX0U/view?usp=sharing). – EmmyS Mar 27 '16 at 04:05
  • 1
    unfortunately, if you can't run it in the debugger, all bets are off and you have a bigger problem – Scott Sosna Mar 27 '16 at 12:55