[英]Why does data from Firestore DB returns as 'null' in FirestoreRecyclerAdapter?
After being successful with writing and reading data from Firestore, I am now trying to display that data in a RecyclerView
by utilizing FirestoreRecyclerAdapter.在从 Firestore 写入和读取数据成功后,我现在尝试使用 FirestoreRecyclerAdapter 在RecyclerView
中显示该数据。 However, in my onBindViewHolder
, where I'm trying to set a textView with data from the database, I'm getting a NullPointerException, where my Client name is null.但是,在我的onBindViewHolder
中,我尝试使用数据库中的数据设置 textView,我得到了 NullPointerException,其中我的客户端名称是 null。
Here is my FirestoreAdapter class:这是我的 FirestoreAdapter class:
public class FirestoreAdapter extends FirestoreRecyclerAdapter<ServiceOrder, FirestoreAdapter.ViewHolder> {
public FirestoreAdapter(@NonNull FirestoreRecyclerOptions<ServiceOrder> options) {
super(options);
}
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull ServiceOrder model) {
holder.osIdItem.setText(String.valueOf(getItem(position).getId()));
holder.osClientItem.setText(getItem(position).getClient().getName()); //Line with error
holder.osDateItem.setText(getItem(position).getDate());
holder.osValueItem.setText(String.valueOf(getItem(position).getTotalValue()));
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.layout_os_item, parent, false);
return new FirestoreAdapter.ViewHolder(view);
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView osIdItem;
private TextView osClientItem;
private TextView osDateItem;
private TextView osValueItem;
public ViewHolder(View itemView) {
super(itemView);
osIdItem = itemView.findViewById(R.id.osIDItem);
osClientItem = itemView.findViewById(R.id.osClientNameItem);
osDateItem = itemView.findViewById(R.id.osDateItem);
osValueItem = itemView.findViewById(R.id.osValueItem);
}
}
}
Here is my Logcat这是我的 Logcat
2022-09-09 09:58:38.479 1147-1147/com.leonardomaito.autocommobile E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.leonardomaito.autocommobile, PID: 1147
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.leonardomaito.autocommobile.models.Client.getName()' on a null object reference
at com.leonardomaito.autocommobile.adapters.FirestoreAdapter.onBindViewHolder(FirestoreAdapter.java:27)
at com.leonardomaito.autocommobile.adapters.FirestoreAdapter.onBindViewHolder(FirestoreAdapter.java:18)
at com.firebase.ui.firestore.FirestoreRecyclerAdapter.onBindViewHolder(FirestoreRecyclerAdapter.java:157)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7254)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7337)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6194)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6460)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6300)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6296)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1631)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4309)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4012)
at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:2028)
at androidx.recyclerview.widget.RecyclerView$1.run(RecyclerView.java:417)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:655)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
My Client
class is using a Builder design pattern, along with the default constructor as required by Firestore, and a Parcelable for transfering data through Activities, I'm only adding this since I'm not sure if it could impact how Firestore is reading my data.我的Client
class 正在使用 Builder 设计模式,以及 Firestore 所需的默认构造函数,以及用于通过活动传输数据的 Parcelable,我只是添加它,因为我不确定它是否会影响 Firestore 读取我的方式数据。
So, how come I can use read and write data to the database, but I can't seem to display it?那么,为什么我可以使用读写数据到数据库,但我似乎无法显示呢? I have a Client
'name' in my database, shouldn't it be displaying that?我的数据库中有一个Client
“名称”,它不应该显示吗?
If it helps, my ServiceOrder
class requires a Vehicle
and a Client
object in order to be built.如果有帮助,我的ServiceOrder
class 需要Vehicle
和Client
object 才能构建。
This is how my data is structured in Firestore:这就是我的数据在 Firestore 中的结构方式:
Thank you.谢谢你。
EDIT编辑
As requested, the Firestore Reference:根据要求,Firestore 参考:
public class OsActivity extends AppCompatActivity {
private FirestoreAdapter listAdapter;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CollectionReference osRef = db.collection("cliente");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_os);
setupRecyclerView();
}
private void setupRecyclerView() {
RecyclerView recyclerView = findViewById(R.id.recyclerViewOs);
Query query = osRef.orderBy("ServiceOrder",
Query.Direction.ASCENDING);
FirestoreRecyclerOptions<ServiceOrder> options =
new FirestoreRecyclerOptions.Builder<ServiceOrder>()
.setQuery(query, ServiceOrder.class)
.build();
listAdapter = new FirestoreAdapter(options);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(listAdapter);
}
@Override
protected void onStart() {
super.onStart();
listAdapter.startListening();
}
@Override
protected void onStop() {
super.onStop();
listAdapter.stopListening();
}
Ran another debugger and got the following message No setter/field for ServiceOrder found on class com.leonardomaito.autocommobile.models.ServiceOrder
运行另一个调试器并收到以下消息No setter/field for ServiceOrder found on class com.leonardomaito.autocommobile.models.ServiceOrder
Database Schema数据库模式
ServiceOrder Class服务订单 Class
public class ServiceOrder {
public Client client;
public Vehicle vehicle;
private String service;
private String observation;
private String paymentForm;
private String date;
private double totalValue;
private int id;
public ServiceOrder() {
}
private ServiceOrder(ServiceOrderBuilder serviceOrderBuilder){
this.client = serviceOrderBuilder.client;
this.vehicle = serviceOrderBuilder.vehicle;
this.service = serviceOrderBuilder.service;
this.paymentForm = serviceOrderBuilder.paymentForm;
this.observation = serviceOrderBuilder.observation;
this.totalValue = serviceOrderBuilder.value;
this.date = serviceOrderBuilder.date;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public double getTotalValue() {
return totalValue;
}
public void setTotalValue(double totalValue) {
this.totalValue = totalValue;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public Vehicle getVehicle() {
return vehicle;
}
public void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getObservation() {
return observation;
}
public void setObservation(String observation) {
this.observation = observation;
}
public String getPaymentForm() {
return paymentForm;
}
public void setPaymentForm(String paymentForm) {
this.paymentForm = paymentForm;
}
public static class ServiceOrderBuilder {
private Vehicle vehicle;
private Client client;
private final String service;
private final String paymentForm;
private final int id;
private final double value;
private final String date;
private String observation;
public ServiceOrderBuilder(Client client, Vehicle vehicle,
String service, String paymentForm,
int id, double value, String date) {
this.client = client;
this.vehicle = vehicle;
this.service = service;
this.paymentForm = paymentForm;
this.id = id;
this.value = value;
this.date = date;
}
public ServiceOrder.ServiceOrderBuilder observation(String observation) {
this.observation = observation;
return this;
}
public ServiceOrder build() {
ServiceOrder serviceOrder = new ServiceOrder(this);
return serviceOrder;
}
}
}
Since you're using the Firebase-UI library, when you're using the following method call:由于您使用的是 Firebase-UI 库,因此当您使用以下方法调用时:
.setQuery(query, ServiceOrder.class)
It means that you're trying to map all documents that are returned by the query into objects of type ServiceOrder
.这意味着您正在尝试将查询返回的所有文档 map 转换为ServiceOrder
类型的对象。 But this is actually not possible because your actual document looks like this:但这实际上是不可能的,因为您的实际文档如下所示:
clienteTeste (document)
|
--- ServiceOrder (map)
|
--- client: {...} (map)
|
--- date: "09/09/2022"
|
--- //other fields
Instead of this:而不是这个:
clienteTeste (document)
|
--- client: {...} (map)
|
--- date: "09/09/2022"
|
--- //other fields
See, there is no ServiceOrder
extra object?看,没有ServiceOrder
额外的object? This would be the simplest solution for solving this issue, in which the fields should be added directly into the document not inside a map.这将是解决此问题的最简单解决方案,其中字段应直接添加到文档中,而不是map 内。
If you however cannot change the document structure, which I doubt, since there is only one (test) document present there, then you should consider using encapsulation by creating another class with a single field called ServiceOrder
which should be of type ServiceOrder
.但是,如果您无法更改文档结构,我对此表示怀疑,因为那里只有一个(测试)文档,那么您应该考虑通过创建另一个 class 来使用封装,其中包含一个名为ServiceOrder
的单个字段,该字段的类型应该是ServiceOrder
。 And then map each document into an object of this new class.然后将map的每一个文件变成一个object这个新的class。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.