Search code examples
javaandroidfirebase-realtime-databaseandroid-recyclerviewfirebaseui

Displaying CardViews inside a RecyclerView using FirebaseUI and Firebase database


I am trying to display CardViews inside a RecyclerView, each card will represent a cheese object. This cheese object has 6 instance variables. This is my Cheese.java :

public class Cheese {
private String CheeseName;
private String CheeseCountryOfOrigin;
private String CheeseDayMade;
private String CheeseDayExpire;
private String CheeseDescription ;
private String CheesePrice;


public Cheese(){}  //Required for firebase

public Cheese(String CheeseName, String CheeseCountryOfOrigin, String CheeseDayMade, String CheeseDayExpire, String CheeseDescription, String CheesePrice) {
    this.CheeseName = CheeseName;
    this.CheeseCountryOfOrigin = CheeseCountryOfOrigin;
    this.CheeseDayMade = CheeseDayMade;
    this.CheeseDayExpire = CheeseDayExpire;
    this.CheeseDescription = CheeseDescription;
    this.CheesePrice = CheesePrice;
}

public String getCheeseName() {
    return CheeseName;
}

public String getCheeseCountryOfOrigin() {
    return CheeseCountryOfOrigin;
}

public String getCheeseDayMade() {
    return CheeseDayMade;
}

public String getCheeseDayExpire() {
    return CheeseDayExpire;
}

public String getCheeseDescription() {
    return CheeseDescription;
}

public String getCheesePrice() {
    return CheesePrice;
}

} and this is my cheese_card.xml (I hardcoded some android:text for better understanding): cheese_card.xml

my RecyclerView is in a fragment.

This is my fragment: fragment_cheeses_list.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cheeses_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
</android.support.v7.widget.RecyclerView>

all my cheese items are already in my Firebase Real-Time Database. To make my life simpler I am trying to use FirebaseUI to populate my RecyclerView with data from my Firebase database.

This is my CheesesListFragment.java, which is displayed in my MainActivity:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.CardView;
import android.support.v7.widget.GridLayoutManager;
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.firebase.ui.database.FirebaseRecyclerAdapter;
import com.firebase.ui.database.FirebaseRecyclerOptions;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;


public class CheeseListFragment extends Fragment {
private static final String TAG = "CheesesListFragment";

private FirebaseDatabase aFirebaseDatabase;
private DatabaseReference aCheesesDatabaseReference;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    Log.e(TAG, "onCreateView Started Successfully");

    //Create the recycler view object
    RecyclerView cheesesRecycler = (RecyclerView) inflater.inflate(R.layout.fragment_cheeses_list, container, false);

    //Add a grid layout manager to the recycler view
    GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 1);
    cheesesRecycler.setLayoutManager(layoutManager);

    cheesesRecycler.setHasFixedSize(true);

    aFirebaseDatabase = FirebaseDatabase.getInstance();
    aCheesesDatabaseReference = aFirebaseDatabase.getReference().child("cheeses");

    //Query the cheeses in firebase db using firebaseUI instead of addChildEventListener
    Query query = aCheesesDatabaseReference;

    //configuration for the FirebaseRecyclerAdapter
    FirebaseRecyclerOptions<Cheese> options =
            new FirebaseRecyclerOptions.Builder<Cheese>()
                    .setQuery(query, Cheese.class)
                    .build();

    FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Cheese, CheeseViewHolder>(options) {
        @Override
        public CheeseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            // Create a new instance of the ViewHolder, in this case we are using a custom
            // layout called R.layout.cheese_card for each item

            CardView cv = (CardView) LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.cheese_card, parent, false);

            return new CheeseViewHolder(cv);
        }

        @Override
        protected void onBindViewHolder(CheeseViewHolder holder, int position, Cheese model) {
            CheeseViewHolder myHolder = (CheeseViewHolder)holder;

            myHolder.cheeseName.setText(model.getCheeseName());
            myHolder.cheeseCountryOfOrigin.setText(model.getCheeseCountryOfOrigin());
            myHolder.cheeseDayMade.setText(model.getCheeseDayMade());
            myHolder.cheeseDayExpire.setText(model.getCheeseDayExpire());
            myHolder.cheeseDescription.setText(model.getCheeseDescription());
            myHolder.cheesePrice.setText(model.getCheesePrice());
        }
    };

    //Set the adapter to the recycle View
    cheesesRecycler.setAdapter(adapter);

    return cheesesRecycler;
}

public static class CheeseViewHolder extends RecyclerView.ViewHolder {
    CardView cardView;

    TextView CheeseName;
    TextView CheeseCountryOfOrigin;
    TextView CheeseDayMade;
    TextView CheeseDayExpire;
    TextView CheeseDescription;
    TextView CheesePrice;

    public CheeseViewHolder (CardView v){
        super(v);
        cardView = v;

        CheeseName = (TextView)cardView.findViewById(R.id.cheese_name);
        CheeseCountryOfOrigin= (TextView)cardView.findViewById(R.id.cheese_origin);
        CheeseDayMade= (TextView)cardView.findViewById(R.id.cheese_day_made);
        CheeseDayExpire= (TextView)cardView.findViewById(R.id.cheese_day_expire);
        CheeseDescription= (TextView)cardView.findViewById(R.id.cheese_description);
        CheesePrice= (TextView)cardView.findViewById(R.id.cheese_price);
    }

}

}

So my questions are: (answering any of them is welcomed and very helpful)

  1. If i get it right, onCreateViewHolder is supposed to make ViewHolders for my Cheese object using my cheese_card.xml . if so, assuming I delete onBindingViewHolder am I suppose to see lots of view holders that look like my cheese_card.xml?

    image description

  2. in onBindingViewHolder in setText : how can I get my TextViews to get a value from my firebase?

  3. I am new to programming and not sure about onCreateViewHolder, onBindingHolder and cheesesViewHolder.I am not sure what every code I writed there means as some of them are copy-pasted.If I got it all wrong, can you please explain how can I reach my desired outcome, and what I did wrong?

Thank you, in advance :)


Solution

  • Modify onBindingViewHolder and cheesesViewHolder. Because in onBindingViewHolder you will bind data with Views not Views with they ids. Bind Views with they ids inside cheesesViewHolder. For example:

    CardView cardView;
    TextView cheese_name;
    TextView cheese_origin;
    
    public CheeseViewHolder(CardView v) {
        super(v);
        cardView = v;
        cheese_name = (TextView) cardView.findViewById(R.id.cheese_name);
        cheese_origin = (TextView) cardView.findViewById(R.id.cheese_origin);
        // and so on...
    }
    

    Then inside onBindingViewHolder you will do something like this:

    @Override
        protected void onBindViewHolder(CheeseViewHolder holder, int position, Cheese model) {
         cheesesViewHolder myHolder = (cheesesViewHolder)holder;
         myHolder.cheese_name.setText(model.getCheeseName());
         myHolder. cheese_origin.setText(model.getCheeseOrigin());
         //and so on...
    }