auto-value-parcel-adapter处理auto-value类类型化Set遇CREATOR访问问题
你遇到的问题核心在于:AutoValue生成的AutoValue_Amoeba子类中的CREATOR是包私有的(默认访问权限),而且你的抽象类Amoeba本身并没有暴露一个Parcelable.Creator<Amoeba>类型的静态常量,所以在自定义的AmoebaTypeAdapter中无法直接引用Amoeba.CREATOR。
另外,这里其实存在一个对auto-value-parcel用法的误解:对于已经实现Parcelable的类型(比如你的Amoeba类),auto-value-parcel可以自动处理其集合类型(包括Set<Amoeba>)的序列化和反序列化,不需要自定义TypeAdapter。
方案1:移除自定义TypeAdapter(推荐)
直接去掉amoebas()字段上的@ParcelAdapter(AmoebaTypeAdapter.class)注解,让auto-value-parcel自动处理集合的序列化逻辑。它会自动使用Amoeba的Parcelable实现来读写集合元素,无需额外代码。
修改后的Xenarchaeota类:
@AutoValue public abstract class Xenarchaeota implements Parcelable { public abstract Set<Amoeba> amoebas(); public static Builder builder() { return new AutoValue_Xenarchaeota.Builder(); } @AutoValue.Builder public abstract static class Builder { public abstract Builder setAmoebas(Set<Amoeba> value); public abstract Xenarchaeota build(); } }
这样做既简洁又符合auto-value-parcel的设计初衷,避免了手动处理Parcel逻辑的错误。
方案2:如果需要自定义集合类型(比如强制使用TreeSet)
如果你确实需要自定义集合的序列化逻辑(比如确保反序列化后是TreeSet),可以通过以下方式解决CREATOR访问问题:
步骤1:在Amoeba抽象类中暴露CREATOR
在Amoeba类中添加一个public static final的CREATOR,指向AutoValue生成的子类的CREATOR。注意,这个写法需要Amoeba和生成的AutoValue_Amoeba在同一个包下(AutoValue生成的子类默认和抽象类同包):
@AutoValue public abstract class Amoeba implements Parcelable { public abstract String surname(); // 暴露CREATOR,指向AutoValue生成的子类的CREATOR public static final Parcelable.Creator<Amoeba> CREATOR = AutoValue_Amoeba.CREATOR; public static Builder builder() { return new AutoValue_Amoeba.Builder(); } @AutoValue.Builder public abstract static class Builder { public abstract Builder surname(final String value); public abstract Amoeba build(); } }
步骤2:修改TypeAdapter使用Amoeba.CREATOR
现在你的AmoebaTypeAdapter就可以正常使用Amoeba.CREATOR了:
class AmoebaTypeAdapter implements TypeAdapter<Set<Amoeba>> { @Override public Set<Amoeba> fromParcel(Parcel in) { final ArrayList<Amoeba> arrayList = new ArrayList<>(); in.readTypedList(arrayList, Amoeba.CREATOR); return new TreeSet<>(arrayList); } @Override public void toParcel(Set<Amoeba> value, Parcel dest) { final ArrayList<Amoeba> arrayList = new ArrayList<>(value); dest.writeTypedList(arrayList); } }
不过这种写法依赖于AutoValue生成的子类实现,属于间接依赖内部细节,不如方案1优雅,所以优先推荐方案1。
内容的提问来源于stack exchange,提问作者Hector

