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"
}
}
}