5

Basically, what I am trying to do is use a FirebaseRecyclerAdapter and populate the RecyclerView with my custom designed CardView. The code for newer versions has been changed and therefore, I tried implementing it but didn't work. This is the code I use to write a year ago, which worked fine and populated my RecyclerView:

FirebaseRecyclerAdapter<DataClass,DataViewHolder> FBRA= new FirebaseRecyclerAdapter<DataClass, DataViewHolder>(
            DataClass,
            R.layout.myCardView,
            DataViewHolder.class,
            databaseReference
    ) {
        @Override
        protected void populateViewHolder(DataViewHolder viewHolder, DataClass model, int position) {
            viewHolder.setTitle(model.gettitle());
            viewHolder.setDate(model.getDate());
        }
   }; 
  myRecyclerView.setAdapter(FBRA);

And now we have to use something like this, but the problem is this code is not populating my recyclerView (What changes do I need to make here to populate my recyclerView with my cardView?)

@Override
protected void onStart() {
    super.onStart();

    Query query = FirebaseDatabase.getInstance()
            .getReference()
            .child("Official_Services");

    FirebaseRecyclerOptions<ServiceClass> options = new FirebaseRecyclerOptions.Builder<ServiceClass>()
            .setQuery(query, ServiceClass.class)
            .build();

    FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder> FBRA = new FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder>(options) {

        @NonNull
        @Override
        public ServiceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {

            View view = LayoutInflater.from(HomeActivity.this).inflate(R.layout.service_card, parent, false);

            return new ServiceViewHolder(view);

        }

        @Override
        protected void onBindViewHolder(@NonNull ServiceViewHolder holder, int position, @NonNull ServiceClass model) {

            holder.setServiceName(model.getServiceName());

            holder.setServiceCaption(model.getServiceCaption());

        }

    };

    mServiceList.setAdapter(FBRA);

}

Here is my ViewHolder class:

public static class ServiceViewHolder extends RecyclerView.ViewHolder {

    public ServiceViewHolder(View itemView) {

        super(itemView);

        View mView = itemView;

    }

    public void setServiceName(String serviceName) {

        TextView sName = itemView.findViewById(R.id.serviceName);

        sName.setText(serviceName);

    }

    public void setServiceCaption(String serviceCaption) {

        TextView sCaption = itemView.findViewById(R.id.serviceCap);

        sCaption.setText(serviceCaption);
    }

}

And this is my Model class of getters and setters:

public class ServiceClass {

private String serviceName;
private String serviceCode;
private String serviceCaption;
private String serviceIconUrl;

public ServiceClass() {
}

public ServiceClass(String serviceName, String serviceCode, String serviceCaption, String serviceIconUrl) {
    this.serviceName = serviceName;
    this.serviceCode = serviceCode;
    this.serviceCaption = serviceCaption;
    this.serviceIconUrl = serviceIconUrl;
}

public String getServiceName() {
    return serviceName;
}

public String getServiceCode() {
    return serviceCode;
}

public String getServiceCaption() {
    return serviceCaption;
}

public String getServiceIconUrl() {
    return serviceIconUrl;
}

public void setServiceName(String serviceName) {
    this.serviceName = serviceName;
}

public void setServiceCode(String serviceCode) {
    this.serviceCode = serviceCode;
}

public void setServiceCaption(String serviceCaption) {
    this.serviceCaption = serviceCaption;
}

public void setServiceIconUrl(String serviceIconUrl) {
    this.serviceIconUrl = serviceIconUrl;
}

@Override
public String toString() {
    return "ServiceClass{" +
            "serviceName='" + serviceName + '\'' +
            ", serviceCode='" + serviceCode + '\'' +
            ", serviceCaption='" + serviceCaption + '\'' +
            ", serviceIconUrl='" + serviceIconUrl + '\'' +
            '}';
}
}

Now what changes do I need to do?

Here is my entire java file:

public class HomeActivity extends AppCompatActivity {

    private RecyclerView mServiceList;

    private FirebaseDatabase mDatabase;

    private DatabaseReference myRef;

    FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder> FBRA;

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

        BottomNavigationViewEx bottomNavigationViewEx = findViewById(R.id.navViewBar);

        bottomNavigationViewEx.enableAnimation(false);

        bottomNavigationViewEx.enableShiftingMode(false);

        bottomNavigationViewEx.setTextVisibility(false);

        Calligrapher calligrapher = new Calligrapher(this);

        calligrapher.setFont(this, "Helvetica.ttf", true);

        mServiceList = findViewById(R.id.serviceRV);

        mServiceList.setHasFixedSize(true);

        mServiceList.setLayoutManager(new LinearLayoutManager(this));

        mDatabase = FirebaseDatabase.getInstance();

        myRef = mDatabase.getReference().child("Official_Services");

    }

    @Override
    protected void onStart() {
        super.onStart();

        FBRA.startListening();

        Query query = myRef;

        FirebaseRecyclerOptions<ServiceClass> options = new FirebaseRecyclerOptions.Builder<ServiceClass>()
                .setQuery(query, ServiceClass.class)
                .build();

        FBRA = new FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder>(options) {

            @NonNull
            @Override
            public ServiceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {

                View view = LayoutInflater.from(HomeActivity.this).inflate(R.layout.service_card, parent, false);

                return new ServiceViewHolder(view);

            }

            @Override
            protected void onBindViewHolder(@NonNull ServiceViewHolder holder, int position, @NonNull ServiceClass model) {

                holder.setServiceName(model.getServiceName());

                holder.setServiceCaption(model.getServiceCaption());

            }

        };

        mServiceList.setAdapter(FBRA);



    }



    public static class ServiceViewHolder extends RecyclerView.ViewHolder {

        public ServiceViewHolder(View itemView) {

            super(itemView);

            View mView = itemView;

        }

        public void setServiceName(String serviceName) {

            TextView sName = itemView.findViewById(R.id.serviceName);

            sName.setText(serviceName);

        }

        public void setServiceCaption(String serviceCaption) {

            TextView sCaption = itemView.findViewById(R.id.serviceCap);

            sCaption.setText(serviceCaption);
        }

    }

}
Pika Supports Ukraine
  • 3,612
  • 10
  • 26
  • 42
Kaushal
  • 217
  • 1
  • 4
  • 12

2 Answers2

3

In order to be able to display data from the Firebase realtime database you need to start listening for changes and for that you should add the following line of code in the onStart() method:

@Override
protected void onStart() {
    super.onStart();
    FBRA.startListening();
}

To stop listening foir changes you need add the following line of code in the onStop() method like this:

@Override
protected void onStop() {
    super.onStop();
    if(FBRA != null) {
        FBRA.stopListening();
    }
}

Please see my answer from this post where I have explained why you should remove the listener.

P.S. Please also don't forget to make the FBRA a global variable and remove FirebaseRecyclerAdapter<ServiceClass, ServiceViewHolder> from the declaration of the object.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • I added FBRA.startListening(); in onStart(), but now the app is crashing. – Kaushal Mar 06 '19 at 16:22
  • With what error? Have you added the `FBRA` as a global variable? – Alex Mamo Mar 06 '19 at 16:27
  • Yes! this is the error: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.firebase.ui.database.FirebaseRecyclerAdapter.startListening()' on a null object reference at com.newpolicies.redesignedkaushalsplatn.platn.HomeActivity.onStart(HomeActivity.java:64) – Kaushal Mar 06 '19 at 16:29
  • 1
    Change this line `FirebaseRecyclerAdapter FBRA = new FirebaseRecyclerAdapter(options)` with `FBRA = new FirebaseRecyclerAdapter(options)` Does it work now? – Alex Mamo Mar 06 '19 at 16:31
  • Yes I have already changed it by declaring adapter globally! But still it won't works. App is crashing. – Kaushal Mar 06 '19 at 16:34
  • Please show me your changed code. Add it to your question. – Alex Mamo Mar 06 '19 at 16:35
  • 1
    Move this line `FBRA.startListening();` after ` mServiceList.setAdapter(FBRA);`, works? – Alex Mamo Mar 06 '19 at 16:55
  • Yes it is working but now the problem is it is not display the serviceName and serviceCaption, it is just populating the cards. – Kaushal Mar 06 '19 at 17:04
  • 1
    Good to hear that it worked! It means that the initial error disappeared and this are good news :) The fact that the `serviceName` and `serviceCaption` are not displayed sounds as a new issue which basically should be considered another question that cannot be answered in a comment. As a personal guess, I think that you are using a wrong views but in order to follow the rules of this comunity, please post another fresh question using a [MCVE](https://stackoverflow.com/help/mcve), so me and other Firebase developers can help you. – Alex Mamo Mar 06 '19 at 17:07
  • Sorry, it was my small mistake, your answer is perfect, it is now working as I wanted it to, Thanks Man :) – Kaushal Mar 06 '19 at 17:10
  • 1
    Yup! It was really helpful – Kaushal Mar 06 '19 at 17:16
3

This is more of an advice. If you want to continue using the old method to populate your recyclerview ie The "populateViewHolder" method instead of the new "onBindViewHolder" method just use this;

implementation 'com.firebaseui:firebase-ui:1.0.1'

instead of upgraded firebase-ui versions

Martin Mbae
  • 1,108
  • 1
  • 16
  • 27