首页 > 解决方案 > 在侦听器中调用 getValue() 时,android firebase 无法实例化抽象类

问题描述

我有一个装备类,它有一个抽象类作为它的属性之一。当我侦听数据库中的更改时,我收到此错误java.lang.RuntimeException: java.lang.InstantiationException: Can't instantiate abstract class com.example.recouture.Item

 DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
    Query query = reference.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("Outfits");
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) {
                outfits.add(singleSnapshot.getValue(Outfit.class)); //error is here
            }

是否有可能绕过这一点,因为使 Item 非抽象会导致我的其他代码部分出现设计问题。Item 是抽象的,因为它可以包含从 Item 类扩展而来的 Shirt、Pants 等。

服装.java

public class Outfit implements Parcelable{

private List<Item> itemList = new ArrayList<>();
private String mName;
private String mImageUrl;


public Outfit() {}


public Outfit(String mName, String mImageUrl,List<Item> items) {
    this.mName = mName;
    this.mImageUrl = mImageUrl;
    this.itemList = items;
}

public List<Item> getItemList() {
    return itemList;
}

protected Outfit(Parcel in) {
    in.readList(itemList,Item.class.getClassLoader());
    mName = in.readString();
    mImageUrl = in.readString();
}

public static final Creator<Outfit> CREATOR = new Creator<Outfit>() {
    @Override
    public Outfit createFromParcel(Parcel in) {
        return new Outfit(in);
    }

    @Override
    public Outfit[] newArray(int size) {
        return new Outfit[size];
    }
};

public String getmName() {
    return mName;
}

public String getmImageUrl() {
    return mImageUrl;
}

@Override
public String toString() {
    return mName;
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeList(itemList);
    parcel.writeString(mName);
    parcel.writeString(mImageUrl);
}

public void setItemList(List<Item> itemList) {
    this.itemList = itemList;
}

}

public abstract class Item implements Parcelable {

private String mName;

private String mColor;

private String mImageUrl;

private List<TagHolder> tags = new ArrayList<>();

private String mKey;




public Item(){

}



public Item(String mName, String mColor, String mImageUrl) {
    this.mName = mName;
    this.mColor = mColor;
    this.mImageUrl = mImageUrl;
}


protected Item(Parcel in) {
    mName = in.readString();
    mColor = in.readString();
    mImageUrl = in.readString();
    tags = in.createTypedArrayList(TagHolder.CREATOR);
    mKey = in.readString();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(mName);
    dest.writeString(mColor);
    dest.writeString(mImageUrl);
    dest.writeTypedList(tags);
    dest.writeString(mKey);
}

@Override
public int describeContents() {
    return 0;
}


public void setmName(String mName) {
    this.mName = mName;
}

public void setmImageUrl(String mImageUrl) {
    this.mImageUrl = mImageUrl;
}

public List<TagHolder> getTags() {
    return tags;
}

public String getmColor() {
    return mColor;
}

public String getmImageUrl() {
    return mImageUrl;
}

public void setmColor(String mColor) {
    this.mColor = mColor;
}

public String getmName() {
    return mName;
}

public void setTags(List<TagHolder> tags) {
    this.tags = tags;
}

@Exclude // dont need this in our firebase database
public String getKey() {
    return mKey;
}

@Exclude
public void setMkey(String key) {
    mKey = key;
}


public abstract String getCategory();

}

firebase 数据库结构:

userid : {
    outfits : {
        uniqueKey1 : {
            itemList : {
                0: {..}
                1: {...}
            }
                mName : {...}
                mImageUrl : {...}

         } // uniquekey1
         uniqueKey2 : {
            itemList : {
                0: {..}
                1: {...}
            }
                mName : {...}
                mImageUrl : {...}
            } // end unique key 2 
         }
     } //end outfits
} // end user id 

完整的堆栈跟踪:

08-02 00:04:28.191 6353-6353/com.example.recouture E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.recouture, PID: 6353
java.lang.RuntimeException: java.lang.InstantiationException: Can't instantiate abstract class com.example.recouture.Item
    at com.google.android.gms.internal.zzelx.zze(Unknown Source:305)
    at com.google.android.gms.internal.zzelw.zzb(Unknown Source:196)
    at com.google.android.gms.internal.zzelw.zza(Unknown Source:301)
    at com.google.android.gms.internal.zzelw.zza(Unknown Source:60)
    at com.google.android.gms.internal.zzelw.zzb(Unknown Source:0)
    at com.google.android.gms.internal.zzelx.zze(Unknown Source:125)
    at com.google.android.gms.internal.zzelw.zzb(Unknown Source:196)
    at com.google.android.gms.internal.zzelw.zza(Unknown Source:0)
    at com.google.firebase.database.DataSnapshot.getValue(Unknown Source:10)
    at com.example.recouture.Outfit.ViewOutfits$2.onDataChange(ViewOutfits.java:74) // line of my error 
    at com.google.firebase.database.zzp.onDataChange(Unknown Source:7)
    at com.google.android.gms.internal.zzegf.zza(Unknown Source:13)
    at com.google.android.gms.internal.zzeia.zzbyc(Unknown Source:2)
    at com.google.android.gms.internal.zzeig.run(Unknown Source:71)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
 Caused by: java.lang.InstantiationException: Can't instantiate abstract class com.example.recouture.Item
    at java.lang.reflect.Constructor.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
    at com.google.android.gms.internal.zzelx.zze(Unknown Source:53)
    at com.google.android.gms.internal.zzelw.zzb(Unknown Source:196) 
    at com.google.android.gms.internal.zzelw.zza(Unknown Source:301) 
    at com.google.android.gms.internal.zzelw.zza(Unknown Source:60) 
    at com.google.android.gms.internal.zzelw.zzb(Unknown Source:0) 
    at com.google.android.gms.internal.zzelx.zze(Unknown Source:125) 
    at com.google.android.gms.internal.zzelw.zzb(Unknown Source:196) 
    at com.google.android.gms.internal.zzelw.zza(Unknown Source:0) 
    at com.google.firebase.database.DataSnapshot.getValue(Unknown Source:10) 
    at com.example.recouture.Outfit.ViewOutfits$2.onDataChange(ViewOutfits.java:74) 
    at com.google.firebase.database.zzp.onDataChange(Unknown Source:7) 
    at com.google.android.gms.internal.zzegf.zza(Unknown Source:13) 
    at com.google.android.gms.internal.zzeia.zzbyc(Unknown Source:2) 
    at com.google.android.gms.internal.zzeig.run(Unknown Source:71) 
    at android.os.Handler.handleCallback(Handler.java:873) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:193) 
    at android.app.ActivityThread.main(ActivityThread.java:6669) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

标签: javaandroidfirebase-realtime-database

解决方案


您的具体Outfit类具有定义的字段和属性Item

public class Outfit implements Parcelable{
    private List<Item> itemList = new ArrayList<>();

    ...    
    public List<Item> getItemList() 

这意味着 Firebase SDK 将尝试实例化一个Item,这是不可能的,因为它是抽象的。您很可能希望 Firebase 在Item读取数据时实例化正确的(具体)子类型,但它无法知道那是什么子类型。

您要么必须标记Item为非抽象,要么必须将 标记itemList为具有特定的具体子类型Item.


推荐阅读