【问题标题】:Why are some Firestore document values null when called from a FirestoreRecyclerAdapter? (No setter/field for ... found on class)当从 FirestoreRecyclerAdapter 调用时,为什么某些 Firestore 文档值为 null? (在课堂上找不到...的设置器/字段)
【发布时间】:2022-01-24 14:45:46
【问题描述】:

我有一个 Firestore 购买集合,其中包含 companyId、storeId、value、timestamp 和 purchaseId 的文档值。我试图在 FirestoreRecyclerAdapter 中调用这些以显示收据列表。

我的问题是一些文档值(companyId、storId、purchaseId)返回空值,而一些(时间戳、值)根据需要返回值。

日志说,对于这些返回 null 的值,在类 Receipt 上没有设置器/字段。我一直试图在 Stackexchange 上找到答案,但找不到相关的答案。我发现的最接近的是在类 Receipt 中启动值的类类型与数据库中的类型不匹配,但我仔细检查了它们在这两种情况下都是字符串。

对此的任何帮助将不胜感激!

这是 Firestore 结构:

我有一个 Receipt 类:

import com.google.firebase.Timestamp;

public class Receipt {
    private String companyId, purchaseId, storeId, value;
    Timestamp timestamp;

    public Receipt() {
    }

    public Receipt(String companyId, String purchaseId, String storeId, Timestamp timestamp, String value) {
        this.companyId = companyId;
        this.purchaseId = purchaseId;
        this.storeId = storeId;
        this.timestamp = timestamp;
        this.value = value;
    }

    public String getCompany() {
        return companyId;
    }

    public void setCompany(String companyId) {
        this.companyId = companyId;
    }

    public String getPurchase() {
        return purchaseId;
    }

    public void setPurchase(String purchaseId) {
        this.purchaseId = purchaseId;
    }

    public String getStore() {
        return storeId;
    }

    public void setStore(String storeId) {
        this.storeId = storeId;
    }

    public Timestamp getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Timestamp timestamp) {
        this.timestamp = timestamp;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

有一个DisplayReceiptsViewHolder:

import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import com.dummies.rbncr.tapaidhscanner4.R;

public class DisplayReceiptsViewHolder extends RecyclerView.ViewHolder implements 
View.OnClickListener {
    public TextView date, company, amount;
    public Button viewReceiptButton;
    private AdapterView.OnItemClickListener itemClickListener;

    public DisplayReceiptsViewHolder(View itemView){
        super(itemView);
        date = itemView.findViewById(R.id.receipt_list_date_tv);
        company = itemView.findViewById(R.id.receipt_list_company_tv);
        amount = itemView.findViewById(R.id.receipt_list_amount_tv);
        viewReceiptButton = itemView.findViewById(R.id.view_receipt_list_btn);
    }
    @Override
    public void onClick(View v) {
        //itemClickListener.onItemClick(v, v, getAdapterPosition(), false);
    }

    public void setItemClickListener(AdapterView.OnItemClickListener itemClickListener) {
        this.itemClickListener = itemClickListener;
    }
}

然后在 DisplayReceiptsActivity 中,我现在只是检索值并将它们记录到控制台:

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.dummies.rbncr.tapaidhscanner4.Models.Receipt;
import com.dummies.rbncr.tapaidhscanner4.ViewHolders.DisplayReceiptsViewHolder;
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.firebase.Timestamp;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;


public class DisplayReceiptsActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    FirestoreRecyclerAdapter<Receipt, DisplayReceiptsViewHolder> receiptAdapter;

    FirebaseFirestore db = FirebaseFirestore.getInstance();
    FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();

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

        recyclerView = findViewById(R.id.display_receipt_list);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        Query receiptsQuery = FirebaseFirestore.getInstance()
                .collection("Users")
                .document(currentUser.getUid())
                .collection("Purchases");

        FirestoreRecyclerOptions<Receipt> receiptOptions = new FirestoreRecyclerOptions.Builder<Receipt>()
                .setQuery(receiptsQuery, Receipt.class)
                .build();

        receiptAdapter = new FirestoreRecyclerAdapter<Receipt, DisplayReceiptsViewHolder>(receiptOptions) {
            @SuppressLint("SetTextI18n")
            @Override
            protected void onBindViewHolder(@NonNull DisplayReceiptsViewHolder displayReceiptsViewHolder,
                                        int i,
                                        @NonNull Receipt receipt) {

                String company = receipt.getCompany();
                displayReceiptsViewHolder.company.setText(company);
                Log.d("TESTING", "Company = " + company);

                String purchaseId = receipt.getPurchase();
                Log.d("TESTING", "Purchase = " + purchaseId);

                String storeId = receipt.getStore();
                Log.d("TESTING", "Store = " + storeId);

                Timestamp timestamp = receipt.getTimestamp();
                displayReceiptsViewHolder.date.setText(timestamp.toString());
                Log.d("TESTING", "Timestamp = " + timestamp);

                String value = receipt.getValue();
                displayReceiptsViewHolder.amount.setText(value);
                Log.d("TESTING", "Value = " + value);
            }

            @NonNull
            @Override
            public DisplayReceiptsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.receipt_list_item,
                    parent,
                    false);
                return new DisplayReceiptsViewHolder(view);
            }
        };
    }

    @Override
    protected void onStart() {
        super.onStart();
        recyclerView.setAdapter(receiptAdapter);
        receiptAdapter.startListening();
    }

    @Override
    protected void onStop() {
        super.onStop();
        receiptAdapter.stopListening();
    }

    public void returnHome(View view) {
        Intent intent = new Intent(DisplayReceiptsActivity.this, ShopHomeActivity.class);
        startActivity(intent);
    }

    @Override
    public void onBackPressed(){
        Intent intent = new Intent(DisplayReceiptsActivity.this, ShopHomeActivity.class);
        startActivity(intent);
    }

}

这是日志的副本:

2021-12-23 15:48:56.330 2462-2462/com.dummies.rbncr.tapaidhscanner4 W/Firestore: (24.0.0) [CustomClassMapper]: No setter/field for companyId found on class com.dummies.rbncr.tapaidhscanner4.Models.Receipt
2021-12-23 15:48:56.330 2462-2462/com.dummies.rbncr.tapaidhscanner4 W/Firestore: (24.0.0) [CustomClassMapper]: No setter/field for purchaseId found on class com.dummies.rbncr.tapaidhscanner4.Models.Receipt
2021-12-23 15:48:56.330 2462-2462/com.dummies.rbncr.tapaidhscanner4 W/Firestore: (24.0.0) [CustomClassMapper]: No setter/field for storeId found on class com.dummies.rbncr.tapaidhscanner4.Models.Receipt
2021-12-23 15:48:56.331 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Company = null
2021-12-23 15:48:56.331 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Purchase = null
2021-12-23 15:48:56.331 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Store = null
2021-12-23 15:48:56.332 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Timestamp = Timestamp(seconds=1640270467, nanoseconds=629000000)
2021-12-23 15:48:56.332 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Value = 0.75
2021-12-23 15:48:56.358 2462-2462/com.dummies.rbncr.tapaidhscanner4 W/Firestore: (24.0.0) [CustomClassMapper]: No setter/field for companyId found on class com.dummies.rbncr.tapaidhscanner4.Models.Receipt
2021-12-23 15:48:56.358 2462-2462/com.dummies.rbncr.tapaidhscanner4 W/Firestore: (24.0.0) [CustomClassMapper]: No setter/field for purchaseId found on class com.dummies.rbncr.tapaidhscanner4.Models.Receipt
2021-12-23 15:48:56.359 2462-2462/com.dummies.rbncr.tapaidhscanner4 W/Firestore: (24.0.0) [CustomClassMapper]: No setter/field for storeId found on class com.dummies.rbncr.tapaidhscanner4.Models.Receipt
2021-12-23 15:48:56.359 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Company = null
2021-12-23 15:48:56.360 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Purchase = null
2021-12-23 15:48:56.360 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Store = null
2021-12-23 15:48:56.360 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Timestamp = Timestamp(seconds=1640273317, nanoseconds=835000000)
2021-12-23 15:48:56.360 2462-2462/com.dummies.rbncr.tapaidhscanner4 D/TESTING: Value = 0.75

【问题讨论】:

    标签: java android firebase google-cloud-firestore


    【解决方案1】:

    好的 - 所以我通过将 Receipt 类中的 getter 和 setter 的名称编辑为与变量名称相同来解决了这个问题。我不确定为什么会这样,但确实有效:

    import com.google.firebase.Timestamp;
    
    public class Receipt {
        private String companyId, purchaseId, storeId, value;
        Timestamp timestamp;
    
        public Receipt() {
        }
    
        public Receipt(String companyId, String purchaseId, String storeId, Timestamp timestamp, String value) {
            this.companyId = companyId;
            this.purchaseId = purchaseId;
            this.storeId = storeId;
            this.timestamp = timestamp;
            this.value = value;
        }
        
        // updated from getCompany()
        public String getCompanyId() {
            return companyId;
        }
        
        // updated from setCompany(String companyId)
        public void setCompanyId(String companyId) {
            this.companyId = companyId;
        }
    
        // updated from getPurchase()
        public String getPurchaseId() {
            return purchaseId;
        }
    
        // updated from setPurchase(String purchaseId)
        public void setPurchaseId(String purchaseId) {
            this.purchaseId = purchaseId;
        }
    
        // updated from setStore()
        public String getStoreId() {
            return storeId;
        }
    
        // updated from setStore(String storeId)
        public void setStoreId(String storeId) {
            this.storeId = storeId;
        }
    
        public Timestamp getTimestamp() {
            return timestamp;
        }
    
        public void setTimestamp(Timestamp timestamp) {
            this.timestamp = timestamp;
        }
    
        public String getValue() {
            return value;
        }
    
        public void setValue(String value) {
            this.value = value;
        }
    
    }
    

    【讨论】:

    • Firebase 根据 JavaBean naming conventions 使用 getter 和 setter 来确定属性名称。这些伪属性决定了 Receipt 类的公共契约,而不是私有/非公共字段。或者,您可以定义 public 字段而不定义 getter/setter,然后 Firestore 将使用公共字段将数据从/映射到数据库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    相关资源
    最近更新 更多