从Adapter向非创建源Activity传递嵌套对象ArrayList为空的问题
问题分析与修复方案
看起来你在通过Adapter向非来源Activity传递嵌套Parcelable对象的ArrayList时踩了几个Parcelable实现的坑,导致对象列表始终为null。我帮你梳理下核心问题并给出修复方案:
1. Rate类的致命笔误
这是导致列表为null的最关键原因:
- 构造函数名称错误:你把Rate类的构造函数写成了
protected RateCard(Parcel in),但类名是Rate!这会导致CREATOR里的new Rate(in)调用失败,根本无法正确创建Rate实例 - 成员变量名不匹配:类里定义的是
private List<Rule> rateRules,但构造函数里写成了in.readList(this.rateCardRules, ...),数据根本没写到正确的变量上 - List未初始化:如果原List是null,
in.readList没办法把数据写入null对象,必须先初始化集合
修正后的Rate类代码:
public class Rate implements Parcelable{ public final static Parcelable.Creator<Rate> CREATOR = new Creator<Rate>() { @SuppressWarnings({ "unchecked" }) public Rate createFromParcel(Parcel in) { return new Rate(in); } public Rate[] newArray(int size) { return (new Rate[size]); } }; @SerializedName("header") @Expose private String header; @SerializedName("body") @Expose private List<Body> body = null; @SerializedName("footer") @Expose private String footer; @SerializedName("type") @Expose private String rateCardType; @SerializedName("rules") @Expose private List<Rule> rateRules = null; // 修正构造函数名称,和类名保持一致 protected Rate(Parcel in) { this.header = ((String) in.readValue((String.class.getClassLoader()))); // 先初始化List再读取,避免null无法写入数据 this.body = new ArrayList<>(); in.readList(this.body, (Body.class.getClassLoader())); this.footer = ((String) in.readValue((String.class.getClassLoader()))); this.rateCardType = ((String) in.readValue((String.class.getClassLoader()))); // 修正变量名,同时初始化List this.rateRules = new ArrayList<>(); in.readList(this.rateRules, (Rule.class.getClassLoader())); } public Rate() { } // 保留你原有的getter/setter方法 public List<Rule> getRateCardRules() { return rateRules; } public void setRateCardRules(List<Rule> rateRules) { this.rateRules = rateRules; } public String getHeader() { return header; } public void setHeader(String header) { this.header = header; } public List<Body> getBody() { return body; } public void setBody(List<Body> body) { this.body = body; } public String getFooter() { return footer; } public void setFooter(String footer) { this.footer = footer; } public String getRateCardType() { return rateCardType; } public void setRateCardType(String rateCardType) { this.rateCardType = rateCardType; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeValue(header); dest.writeList(body); dest.writeValue(footer); dest.writeValue(rateCardType); dest.writeList(rateRules); } @Override public int describeContents() { return 0; } }
2. Rule类的潜在问题
Rule类的读写顺序看起来是对的,但同样存在List未初始化的问题,修复后更稳妥:
修正后的Rule类代码:
public class Rule implements Parcelable{ public final static Parcelable.Creator<Rule> CREATOR = new Creator<Rule>() { @SuppressWarnings({ "unchecked" }) public Rule createFromParcel(Parcel in) { return new Rule(in); } public Rule[] newArray(int size) { return (new Rule[size]); } }; @SerializedName("rule") @Expose private DataRows ruleData; @SerializedName("rule_conditions") @Expose private List<DataRows> ruleConditions; @SerializedName("slots") @Expose private List<DataRows> slots; @SerializedName("header") @Expose private DataRows header; protected Rule(Parcel in) { // 初始化List再读取数据 this.ruleConditions = new ArrayList<>(); in.readList(this.ruleConditions, (DataRows.class.getClassLoader())); this.slots = new ArrayList<>(); in.readList(this.slots, (DataRows.class.getClassLoader())); this.ruleData = in.readParcelable((DataRows.class.getClassLoader())); this.header = in.readParcelable((DataRows.class.getClassLoader())); } public Rule() { } // 保留你原有的getter/setter方法 public DataRows getRuleData() { return ruleData; } public void setRuleData(DataRows ruleData) { this.ruleData = ruleData; } public List<DataRows> getRuleConditions() { return ruleConditions; } public void setRuleConditions(List<DataRows> ruleConditions) { this.ruleConditions = ruleConditions; } public List<DataRows> getSlots() { return slots; } public void setSlots(List<DataRows> slots) { this.slots = slots; } public DataRows getHeader() { return header; } public void setHeader(DataRows header) { this.header = header; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeList(ruleConditions); dest.writeList(slots); dest.writeParcelable(ruleData, flags); dest.writeParcelable(header, flags); } @Override public int describeContents() { return 0; } }
3. DataRows类(无需修改)
你的DataRows类实现是正确的,不需要调整。
最后,确保传递和接收数据的方式正确
在Adapter中传递数据时,用putParcelableArrayListExtra:
Intent intent = new Intent(context, YourTargetActivity.class); // 注意要传入ArrayList类型,不能直接传List intent.putParcelableArrayListExtra("KEY_RATE_LIST", new ArrayList<>(yourRateList)); context.startActivity(intent);
在目标Activity中接收:
ArrayList<Rate> rateList = getIntent().getParcelableArrayListExtra("KEY_RATE_LIST");
核心总结
- 构造函数名称必须和类名完全一致,这是Parcelable实例化的基础
- 读写Parcel的顺序必须严格对应,写的顺序和读的顺序不能乱
- List类型的成员变量,读取前一定要先初始化(new一个ArrayList),否则null对象无法接收数据
- 变量名要仔细核对,避免笔误导致数据写到错误的变量上
内容的提问来源于stack exchange,提问作者user1002448
相关产品推荐
相关产品推荐

