0

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 :)

Richard Miller
  • 576
  • 1
  • 7
  • 18

2 Answers2

0

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...
}
Yupi
  • 4,402
  • 3
  • 18
  • 37
  • I tried the above suggestion, however, my RecyclerView doesn't show any card when I run the code – Richard Miller Feb 01 '18 at 01:26
  • There could be plenty reasons for that. I suggested you how to fix adapter code and still that doesn’t mean app will run successfully because on some other place there could be issue also. For example: `cheesesRecycler.setHasFixedSize(true);` - is missing and try to use `LinearLayoutManager` instead of `GridLayoutManager` – Yupi Feb 01 '18 at 09:44
  • thank you @Yupi , I updated my code but without the GridLayout as I plan to change the layout to use 2 cards in a row – Richard Miller Feb 01 '18 at 10:57
  • not yet, is there any additional information I should give? a log or data you might need? – Richard Miller Feb 01 '18 at 11:03
  • Yes if you get exceptions that would be helpful to post stack trace of exception. And how is your `static class cheesesViewHolder` different then its constructor `public CheeseViewHolder`? Shouldn't it be the same? like both `CheeseViewHolder` – Yupi Feb 01 '18 at 11:05
  • I don't get any exceptions. as for the class name, you are right, I have changed it but the cards still doesn't show in my recyclerview – Richard Miller Feb 01 '18 at 11:15
  • What is the purpose of `return cheesesRecycler;`? You don't need that. – Yupi Feb 01 '18 at 11:21
  • I get _Missing return statement_ if I don't have it – Richard Miller Feb 01 '18 at 11:24
  • Ah yeah sorry that is because of `onCreatView` of `Fragment` you need to return inflated `View` – Yupi Feb 01 '18 at 11:25
  • Really hard to say from this code maybe problem is that data is not even downloaded from `Database` try to put `Log` in `onBindViewHolder` for example: `Log.e(TAG, model.getCheeseName());` and see will data will be outputted in `Log` – Yupi Feb 01 '18 at 11:27
  • I don't get any Log at all when I try to put a Log inside _onCreateViewHolder_ like this: Log.e(TAG, "onCreateViewHolder started"); Or a log in _onBindViewHolder_ like this: Log.e(TAG, "onBindViewHolder started"); – Richard Miller Feb 01 '18 at 11:35
  • Then something is messed up beside the adapter code. – Yupi Feb 01 '18 at 11:39
0

I was able to eventually fix my problem and get onCreateViewHolder and onBindViewHolder to start simply by adding

adapter.startListening();

to my onStart method. like this:

    @Override
public void onStart() {
    super.onStart();
    Log.e(TAG,"onStart Started Successfully");
    adapter.startListening();
}

And I edited the code using @Yupi suggestion.

Richard Miller
  • 576
  • 1
  • 7
  • 18