1

I am using Firebase Real time database to populate a recyclerview using the material design card view to display different categories of businesses.

In my navigation drawer I have a list of categories that I will have display different kinds of businesses in my area. As of now I only have one fragment that inflates a view to make sure everything works before I get to the other fragments nav categories and here is a screenshot of the Firebase Database database

When I tap on the "accounting / finance" fragment I get an from Android Studios displaying java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference

This takes me to the getItemCount() in my Recyclerview Adapter class. It returns null because the Model class is null. If I hard code a number like 10 to return in getItemCount() it will then error in onBindViewHolder() where I get the position from the list of businesses. Here is the my code that I believe pertains to the problem. Some code will be removed to keep it as concise as possible.

This is the main activity where I get the data from the Firebase Database and try to assign the data to The Businesses.java model class to be read from the recyclerview.

public class HomeScreenActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener
{
    private List<Businesses> mBusinesses = new ArrayList<>();
    private RecyclerViewAdapter mRecyclerViewAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home_screen);

        DatabaseReference database = FirebaseDatabase.getInstance().getReference().child("accounting");
        database.addChildEventListener(new ChildEventListener()
        {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s)
            {
                Businesses model = dataSnapshot.getValue(Businesses.class);
                mBusinesses.add(model);
            }
        });
    }


    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item)
    {
        int id = item.getItemId();
        displaySelectedScreen(id);
        item.setCheckable(true);
        setTitle(item.getTitle());

        return true;
    }

    private void displaySelectedScreen(int itemId)
    {
        Fragment fragment = null;

        switch (itemId)
        {
            case R.id.nav_accounting_finance:
                fragment = new AccountingFinanceFrag();
                break;
        }

        if (fragment != null)
        {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.fragment_container, fragment);
            ft.commit();
        }
    }

}

Here is my Model class the is returning null when the recyclerview is called from the "accounting / finance" fragment

@IgnoreExtraProperties
public class Businesses
{
    public String Name;
    public String About;
    public String Picture;
    public long Phone;

    public Businesses()
    {

    }

    public Businesses(String name, String about, String picture)
    {
        Name = name;
        About = about;
        Picture = picture;
    }
}

This is my Recyclerview Adapter class where I get the null Model object that should have the data from the Firebase Database.

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecViewHolder>
{
    private Context mContext;
    private List<Businesses> mBusinesses;

    public RecyclerViewAdapter(Context context, List<Businesses> businesses)
    {
        mContext = context;
        mBusinesses = businesses;
    }

    @Override
    public RecViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        View view = inflater.inflate(R.layout.card, parent, false);
        return new RecViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecViewHolder holder, int position)
    {
        Businesses businesses = mBusinesses.get(position);
        holder.mName.setText(businesses.Name);
        holder.mAbout.setText(businesses.About);
        holder.bindGalleryItem(businesses);
    }

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

    public class RecViewHolder extends RecyclerView.ViewHolder
    {
        private CardView mCardView;
        private Businesses mBusinesses;
        private ImageView mImageView;
        private TextView mName, mAbout;

        RecViewHolder(View itemView)
        {
            super(itemView);
            mCardView = (CardView) itemView.findViewById(R.id.card_view);
            mImageView = (ImageView) itemView.findViewById(R.id.buisness_image);
            mName = (TextView) itemView.findViewById(R.id.business_name);
            mAbout = (TextView) itemView.findViewById(R.id.buisness_about);
        }

        public void bindGalleryItem(Businesses businesses)
        {
            mBusinesses = businesses;
            Glide.with(mContext)
                    .load(businesses.Picture)
                    .placeholder(R.mipmap.ic_launcher)
                    .diskCacheStrategy(DiskCacheStrategy.RESULT)
                    .override(200, 200)
                    .into(mImageView);
        }
    }
}

And this is the fragment where the recyclerview is being inflated.

public class AccountingFinanceFrag extends Fragment
{
    private List<Businesses> mBusinesses;
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private TextView mNameText, mAboutText;
    private ImageView mImageView;

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

        mNameText = (TextView) v.findViewById(R.id.business_name);
        mAboutText = (TextView) v.findViewById(R.id.buisness_about);
        mImageView = (ImageView) v.findViewById(R.id.buisness_image);

        mRecyclerView = (RecyclerView) v.findViewById(R.id.fragment_recyclerview);
        mAdapter = new RecyclerViewAdapter(getContext(), mBusinesses );
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        return v;
    }
}

The JSON file for the Database

 {
  "accounting" : {
    "buisness_0" : {
      "About" : "dummy text",
      "Address" : "123 test ave test, test 00000",
      "Email" : "test@example.com",
      "Name" : "Test test",
      "Owner" : "Test owner",
      "Phone" : 4120000000,
      "Picture" : "add link"
    },
    "business_1" : {
      "About" : "dummy text",
      "Address" : "123 test ave test, test 00000",
      "Email" : "test@example.com",
      "Name" : "Test test",
      "Owner" : "Test owner",
      "Phone" : 4120000000,
      "Picture" : "add link"
    }
  }
}
AL.
  • 36,815
  • 10
  • 142
  • 281
  • screenshot for your Firebase Database Please – Elsunhoty Apr 09 '17 at 18:39
  • @Elsunhoty I am getting the data from the database. I am able to see it when I debug and place a breakpoint on the `Businesses model = dataSnapshot.getValue(Businesses.class)` line. But I updated the code with a screenshot – user3920525 Apr 09 '17 at 18:52
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) –  Apr 09 '17 at 18:57
  • You've included a picture of the JSON tree in your question. Please replace that with the actual JSON as text, which you can easily get by clicking the Export JSON link in [your Firebase Database console](https://console.firebase.google.com/project/_/database/data/). Having the JSON as text makes it searchable, allows us to easily use it to test with your actual data and use it in our answer and in general is just a Good Thing to do. (@Elsunhoty: please ask for JSON text instead of screenshots going forward) – Frank van Puffelen Apr 09 '17 at 19:02
  • @FrankvanPuffelen I updated the code, but I'm sure it isn't a problem with the database as I get a the data in onChildAdded(). – user3920525 Apr 09 '17 at 19:39

1 Answers1

0

mBusinesses in your Activity and mBusinesses in your Fragment are different things and that's where the confusion has happened.

In your Activity you initialise and add entries to mBusinesses, but when creating the RecyclerView you pass it the Fragment's mBusinesses object which hasn't been initialised or had any data added to it, hence NullPointerException!

To do this the fragment needs to have the data to give to the RecyclerView, perhaps by loading the data in the Fragment, or the Activity passing data to the Fragment or some other way.

Lewis McGeary
  • 7,692
  • 2
  • 40
  • 46