Skip to content
Advertisement

Firestore does not query on every Listview custom adapter

So this is the source code of my adapter:

package com.example.consigness;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import androidx.annotation.NonNull;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;

import java.util.List;

public class ConsignmentAdapter extends ArrayAdapter<Consignment> {

    TextView title_cList;
    TextView consignor_cList;
    TextView recipient_cList;
    TextView desc_cList;
    TextView status_cList;

    //get Database
    FirebaseFirestore db = FirebaseFirestore.getInstance();

    User con;
    User rec;

    public ConsignmentAdapter(Context context, List<Consignment> object){
        super(context,0, object);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){

        if(convertView == null){
            convertView =  ((Activity)getContext()).getLayoutInflater().inflate(R.layout.consignment_list,parent,false);
        }

        title_cList = convertView.findViewById(R.id.cTitle_cList);
        consignor_cList = convertView.findViewById(R.id.cCons_cList);
        recipient_cList = convertView.findViewById(R.id.cRec_cList);
        desc_cList = convertView.findViewById(R.id.cDesc_cList);
        status_cList = convertView.findViewById(R.id.cStatus_cList);

        Consignment consignment = getItem(position);

        title_cList.setText(consignment.getTitle());

        consignor_cList.setText("By: "+consignment.getConsignee());
        readData(new FirestoreCallBack() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onCallback(User user) {
                Log.d("CONSIGNOR READ OUTSIDE", con.getFname());
                consignor_cList.setText("By: "+con.getFname()+": "+con.getPost()+" at "+con.getCname());
            }
        }, consignment.getConsignee());


        recipient_cList.setText("To: "+consignment.getRecipient());
        readRec(new FirestoreCallBack() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onCallback(User user) {
                Log.d("RECIPIENT READ OUTSIDE", rec.getFname());
                recipient_cList.setText("To: "+rec.getFname()+": "+rec.getPost()+" at "+rec.getCname());
            }
        }, consignment.getRecipient());


        desc_cList.setText(consignment.getDesc());
        status_cList.setText("Status: "+consignment.getStatus());

        return convertView;
    }

    private interface FirestoreCallBack{
        void onCallback(User user);
    }

    private void readData(ConsignmentAdapter.FirestoreCallBack firestoreCallBack, String id){
        db.collection("Users")
                .whereEqualTo("uid", id)
                .get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        if (task.isSuccessful()) {
                            for (QueryDocumentSnapshot document : task.getResult()) {
                                Log.d("CHECK", document.getId() + " => " + document.getData());
                                User user = document.toObject(User.class);
                                con = user;
                            }
                            firestoreCallBack.onCallback(con);
                        } else {
                            Log.d("CHECK", "Error getting documents: ", task.getException());
                        }
                    }
                });
    }

    private void readRec(ConsignmentAdapter.FirestoreCallBack firestoreCallBack, String id){
        db.collection("Users")
                .whereEqualTo("uid", id)
                .get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        if (task.isSuccessful()) {
                            for (QueryDocumentSnapshot document : task.getResult()) {
                                Log.d("CHECK", document.getId() + " => " + document.getData());
                                User user = document.toObject(User.class);
                                rec = user;
                            }
                            firestoreCallBack.onCallback(rec);
                        } else {
                            Log.d("CHECK", "Error getting documents: ", task.getException());
                        }
                    }
                });
    }
}

What I am trying to do is, change the value of two of my Textviews, consignor_cList and recipient_cList from a firestore query.

Initially, both these textviews are having text value as String uid of my firestore document. I want to use these id, query the whole document and use the document data into the textviews.

Before:

consignor_cList.setText("By: "+consignment.getConsignee());

After:

 readData(new FirestoreCallBack() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onCallback(User user) {
                Log.d("CONSIGNOR READ OUTSIDE", con.getFname());
                consignor_cList.setText("By: "+con.getFname()+": "+con.getPost()+" at "+con.getCname());
            }
        }, consignment.getConsignee());

I am using a Firestore callBack function for this.

PROBLEM: Its not that the code is not working. It is. I can see from my log that my program is having successful queries. Then these queries are supposed to setText to by Textview. BUT BUT BUT, its only happening for the first list item and not the rest, sometimes with the first and last item and not the rest.

This has to be my senior project. I wish some genius come up tonight and give me a solution.

I will also share a screenshot of the output.

enter image description here

Advertisement

Answer

You should not store the individual row views as class members in the adapter, nor should the User be stored there, since they will be overridden every time a row is created. Instead of this

TextView title_cList;
//... later in getView()
title_cList = convertView.findViewById(R.id.cTitle_cList);

use this inside getView() and remove the views as class members.

TextView title_cList = convertView.findViewById(R.id.cTitle_cList);

The code in getView() is called for every row, but your callback is run later after the class member was changed to refer to a different row.

You should probably also remove these from the adapter (although this might not cause the current errors, it could introduce other errors if you tried to use them for anything later):

User con;
User rec;

since those can change for each row, and instead use local variables in the callback, probably something like this:

for (QueryDocumentSnapshot document : task.getResult()) {
    Log.d("CHECK", document.getId() + " => " + document.getData());
    User user = document.toObject(User.class);
    firestoreCallBack.onCallback(user);
}
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement