意图getextra中嵌套Parcelable的空指针异常

Posted

技术标签:

【中文标题】意图getextra中嵌套Parcelable的空指针异常【英文标题】:null pointer exception of nested Parcelable in intent getextra 【发布时间】:2020-09-03 03:14:36 【问题描述】:

我有一个嵌套的 parcelable 类(内部有 Provider 类的 Product 类)。我想将 Product 对象发送到另一个具有额外意图的活动。当我有意图时,提供者对象为空。

Outer(Parent) 类是 Product(为方便起见,省略了 setter 和 getter):

public class Product implements Parcelable 

    public static final String KEY_CART_COUNT = "KEY_CART_COUNT";
    private int id;
    private String title;
    private String description;
    @SerializedName("category_id")
    private int categoryId;
    @SerializedName("city_id")
    private int cityId;
    private String fee;
    private String fee2;
    @SerializedName("main_cat")
    private Integer mainCategory;
    @SerializedName("barcode_type")
    private String barcodeType;
    @SerializedName("barcode_text")
    private String barcodeText;
    private String unit;
    private String image;
    @SerializedName("is_active")
    private int isActive;
    @SerializedName("now")
    private long now;

    //*****************************************************************
    @SerializedName("provider_info")
    private Provider provider;
    //*****************************************************************


    @SerializedName("is_bookmarked")
    private boolean isBookmarked;
    @SerializedName("image_url")
    private String imageUrl;
    @SerializedName("exists_number")
    private int existsNumber;
    @SerializedName("buy_limit")
    private int buyLimit;
    private long addToCartTime;
    private int cartCount;

    protected Product(Parcel in) 
        id = in.readInt();
        title = in.readString();
        description = in.readString();
        categoryId = in.readInt();
        cityId = in.readInt();
        fee = in.readString();
        fee2 = in.readString();
        barcodeType = in.readString();
        barcodeText = in.readString();
        unit = in.readString();
        image = in.readString();
        isActive = in.readInt();
        cartCount = in.readInt();
        isBookmarked = in.readByte() != 0;
        mainCategory = in.readInt();
        imageUrl = in.readString();
        existsNumber = in.readInt();
        buyLimit = in.readInt();
        addToCartTime = in.readLong();
        provider = in.readParcelable(Provider.class.getClassLoader());
    




    public Product() 
        this.addToCartTime = Calendar.getInstance().getTime().getTime();
    

    public Product(Product newProduct) 
        this.id = newProduct.id;
        this.title = newProduct.title;
        this.description = newProduct.description;
        this.categoryId = newProduct.categoryId;
        this.cityId = newProduct.cityId;
        this.fee = newProduct.fee;
        this.fee2 = newProduct.fee2;
        this.barcodeType = newProduct.barcodeType;
        this.barcodeText = newProduct.barcodeText;
        this.unit = newProduct.unit;
        this.image = newProduct.image;
        this.isActive = newProduct.isActive;
        this.mainCategory = newProduct.mainCategory;
        this.cartCount = newProduct.cartCount;
        this.isBookmarked = newProduct.isBookmarked;
        this.imageUrl = newProduct.imageUrl;
        this.existsNumber = newProduct.existsNumber;
        this.buyLimit = newProduct.buyLimit;
        this.addToCartTime = newProduct.addToCartTime;
    



    @Override
    public void writeToParcel(Parcel dest, int flags) 
        dest.writeInt(id);
        dest.writeString(title);
        dest.writeString(description);
        dest.writeInt(categoryId);
        dest.writeInt(cityId);
        dest.writeString(fee);
        dest.writeString(fee2);
        dest.writeString(barcodeType);
        dest.writeString(barcodeText);
        dest.writeString(unit);
        dest.writeString(image);
        dest.writeInt(isActive);
        dest.writeInt(cartCount);
        dest.writeInt(mainCategory);
        dest.writeByte((byte) (isBookmarked ? 1 : 0));
        dest.writeString(imageUrl);
        dest.writeInt(existsNumber);
        dest.writeInt(buyLimit);
        dest.writeLong(addToCartTime);
        dest.writeValue(provider);
    

    @Override
    public int describeContents() 
        return 0;
    

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

        @Override
        public Product[] newArray(int size) 
            return new Product[size];
        
    ;





这是我的 Provider 类:

public class Provider implements Parcelable 

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

        @Override
        public Provider[] newArray(int size) 
            return new Provider[size];
        
    ;
    private int id;
    @SerializedName("title")
    private String title;
    @SerializedName("description")
    private String description;
    @SerializedName("admin_id")
    private int admin_id;
    @SerializedName("provider_id")
    private int provider_id;
    @SerializedName("start1")
    private String start1;
    @SerializedName("start2")
    private String start2;
    @SerializedName("end1")
    private String end1;
    @SerializedName("end2")
    private String end2;

    protected Provider(Parcel in) 
        id = in.readInt();
        title = in.readString();
        description = in.readString();
        admin_id = in.readInt();
        provider_id = in.readInt();
        start1 = in.readString();
        start2 = in.readString();
        end1 = in.readString();
        end2 = in.readString();
    



    @Override
    public int describeContents() 
        return 0;
    

    @Override
    public void writeToParcel(Parcel parcel, int i) 
        parcel.writeInt(id);
        parcel.writeString(title);
        parcel.writeString(description);
        parcel.writeInt(admin_id);
        parcel.writeInt(provider_id);
        parcel.writeString(start1);
        parcel.writeString(end1);
        parcel.writeString(start2);
        parcel.writeString(end2);

    

将产品数组发送到 ProductDetailActivity 的代码:

Intent starter = new Intent(context, ProductDetailActivity.class);
starter.putParcelableArrayListExtra(Constants.ACTIVITY_EXTRA_PRODUCTS, new ArrayList<>(products));

context.startActivity(starter);

最后在 ProductDetailActivity 中获取产品:

getIntent().getParcelableArrayListExtra(Constants.ACTIVITY_EXTRA_PRODUCTS)

【问题讨论】:

不确定是否足以解释此问题,但读/写 mainCategory 和 isBookmarked 的顺序混淆了。开始/结束字段也存在类似的排序问题。 你的意思是写和读字段的顺序应该是一样的吗? 当然可以。 Parcel 只是一个数据流。要取回相同的数据,您必须按顺序配对读取和写入。 【参考方案1】:

正如laalto 建议的产品类(或任何 Parcelable 类)中的数据顺序在读写时应相同。我把我的代码改成了这个,它运行良好:

@Override
public void writeToParcel(Parcel dest, int flags) 
    dest.writeInt(id);
    dest.writeString(title);
    dest.writeString(description);
    dest.writeInt(categoryId);
    dest.writeInt(cityId);
    dest.writeString(fee);
    dest.writeString(fee2);
    dest.writeString(barcodeType);
    dest.writeString(barcodeText);
    dest.writeString(unit);
    dest.writeString(image);
    dest.writeInt(isActive);
    dest.writeInt(cartCount);
    dest.writeByte((byte) (isBookmarked ? 1 : 0));// Changed Order 
    dest.writeInt(mainCategory);                  // Changed Order
    dest.writeString(imageUrl);
    dest.writeInt(existsNumber);
    dest.writeInt(buyLimit);
    dest.writeLong(addToCartTime);
    dest.writeLong(now);
    dest.writeParcelable(provider, flags); // **Changed from writeValue to writeParcelable**

【讨论】:

以上是关于意图getextra中嵌套Parcelable的空指针异常的主要内容,如果未能解决你的问题,请参考以下文章

当意图传递给其他活动时,为啥从 parcelable 中得到错误的值?

位图始终在相机意图中返回null

intent.getextra() 正在接收 null 并且 intent.hasextra() 在第二个活动中不起作用

如何将 putExtra() 和 getExtra() 用于字符串数据

带有日历对象的 Android Bundle getExtras

Java嵌套parcelable,无法初始化数组