Reputation: 1522
I am using Firebase UI Recycler Adapter to read data from Firestore
FirestoreRecyclerOptions<Transaction> options =
new FirestoreRecyclerOptions.Builder<Transaction>()
.setQuery(mQuery, Transaction.class)
.setLifecycleOwner(this)
.build();
mAdapter = new TransactionAdapter(options, this, getActivity()) {
@Override
public void onDataChanged() {
// Show/hide content if the query returns empty.
if (getItemCount() == 0) {
mRestaurantsRecycler.setVisibility(View.GONE);
mEmptyView.setVisibility(View.VISIBLE);
} else {
mRestaurantsRecycler.setVisibility(View.VISIBLE);
mEmptyView.setVisibility(View.GONE);
}
}
@Override
public void onError(FirebaseFirestoreException e) {
Log.e("Error", ", not initializing RecyclerView",e);
}
};
Log.w("Test", "No6 query, not initializing RecyclerView");
mRestaurantsRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
mRestaurantsRecycler.setAdapter(mAdapter);
i am getting below exception for some corrupted fields in Firestore
java.lang.RuntimeException: Could not deserialize object. Failed to convert a value of type java.lang.String to double (found in field 'amount')
at com.google.firebase.firestore.util.CustomClassMapper.deserializeError(com.google.firebase:firebase-firestore@@17.1.4:524)
at com.google.firebase.firestore.util.CustomClassMapper.convertDouble(com.google.firebase:firebase-firestore@@17.1.4:427)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToPrimitive(com.google.firebase:firebase-firestore@@17.1.4:304)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-firestore@@17.1.4:215)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToType(com.google.firebase:firebase-firestore@@17.1.4:180)
at com.google.firebase.firestore.util.CustomClassMapper.access$200(com.google.firebase:firebase-firestore@@17.1.4:53)
at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(com.google.firebase:firebase-firestore@@17.1.4:700)
at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.deserialize(com.google.firebase:firebase-firestore@@17.1.4:674)
at com.google.firebase.firestore.util.CustomClassMapper.convertBean(com.google.firebase:firebase-firestore@@17.1.4:503)
at com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-firestore@@17.1.4:242)
at com.google.firebase.firestore.util.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-firestore@@17.1.4:97)
at com.google.firebase.firestore.DocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:203)
at com.google.firebase.firestore.QueryDocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:121)
at com.google.firebase.firestore.DocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:183)
at com.google.firebase.firestore.QueryDocumentSnapshot.toObject(com.google.firebase:firebase-firestore@@17.1.4:101)
at com.firebase.ui.firestore.ClassSnapshotParser.parseSnapshot(ClassSnapshotParser.java:23)
at com.firebase.ui.firestore.ClassSnapshotParser.parseSnapshot(ClassSnapshotParser.java:12)
at com.firebase.ui.common.BaseCachingSnapshotParser.parseSnapshot(BaseCachingSnapshotParser.java:35)
at com.firebase.ui.common.BaseObservableSnapshotArray.get(BaseObservableSnapshotArray.java:52)
at com.firebase.ui.firestore.FirestoreRecyclerAdapter.getItem(FirestoreRecyclerAdapter.java:83)
at com.firebase.ui.firestore.FirestoreRecyclerAdapter.onBindViewHolder(FirestoreRecyclerAdapter.java:125)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6673)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6714)
at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5647)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5913)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5752)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5748)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2232)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1559)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1519)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:614)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3812)
at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3225)
at android.view.View.measure(View.java:22071)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6602)
at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:739)
I know why this error is thrown and i also know i can correct this if i correct my amount field in Firestore Database or by having a Cloud Function to check data validation etc.
But I don't want an App crash experience. Is there any way to catch and add any default value or Null for corrupted values. Showing an individual Null or NA field or an entire empty screen is always better than a Crash.
EDIT: In order to set a default value and avoid Runtime exception i have tried this with my Model class. I still don't know if there is a way to catch this exception.
public double amount;
public double getAmount() {
return amount;
}
// If you change it Object, ClassMapper will not throw any exception and
// You can parse any data type by yourself and also set a default value.
public void setAmount(Object amount) {
try {
// You can also add instanceOf check
this.amount = Double.parseDouble(amount.toString());
} catch (Exception e) {
// Set your default value
this.amount = 0.00;
}
}
Upvotes: 2
Views: 567
Reputation: 138944
I'm answering this question becase of your request from here. So because I see that you are using the Firebase-UI library, there is no need to use a try-catch block. As also @FrankvanPuffelen mentioned in his comment, the simplest thing that you can do, is to override the onError
method in your adapter class like this:
FirestoreRecyclerAdapter adapter = new FirestoreRecyclerAdapter<Chat, ChatHolder>(options) {
@Override
public void onDataChanged() {
//Called each time there is a new query snapshot.
}
@Override
public void onError(FirebaseFirestoreException e) {
//Handle the error
Log.d(TAG, e.getMessage());
}
};
Upvotes: 4