如何捕获java.lang.RuntimeException:无法从Firebase ClassMapper反序列化对象并添加默认值

时间:2018-12-19 10:32:55

标签: android firebase google-cloud-firestore firebaseui

我正在使用Firebase UI回收适配器从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);

对于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)

我知道为什么会引发此错误,并且我也知道如果我在Firestore数据库中更正我的金额字段或通过使用Cloud Function检查数据验证等,就可以更正此问题。

但是我不希望有App崩溃的经历。有没有什么方法可以捕获并添加任何默认值或将Null用于损坏的值。显示单个Null或NA字段或整个空白屏幕总是比Crash更好。

编辑: 为了设置默认值并避免运行时异常,我在Model类中尝试了此操作。我仍然不知道是否有办法捕获此异常。

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;
    }
}

1 个答案:

答案 0 :(得分:3)

根据您here的要求,我正在回答这个问题。因此,由于我看到您正在使用Firebase-UI库,因此无需使用try-catch块。正如@FrankvanPuffelen在他的评论中提到的那样,您可以做的最简单的事情是像这样在适配器类中覆盖onError方法:

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());
    }
};