【问题标题】:Can auto-value-parcel-adapter cope with Typed Set of another auto-value Class?auto-value-parcel-adapter 可以处理另一个 auto-value 类的 Typed Set 吗?
【发布时间】:2018-01-19 15:58:29
【问题描述】:

我正在调查我的 Android 应用程序中的auto-value 及其扩展,即auto-value-parcelauto-value-parcel-adapter

我有这些模型类:-

@AutoValue
public abstract class Xenarchaeota implements Parcelable {

    @ParcelAdapter(AmoebaTypeAdapter.class)
    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();
    }
}

@AutoValue
public abstract class Amoeba implements Parcelable {

    public abstract String surname();

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

}

我的类型适配器是我出现问题的地方

class AmoebaTypeAdapter implements TypeAdapter<Set<Amoeba>> {

    @Override
    public Set<Amoeba> fromParcel(Parcel in) {
        final ArrayList<Amoeba> arrayList = new ArrayList<>();
        in.readTypedList(arrayList, Amoeba.CREATOR); // How to access the CREATOR?
        return new TreeSet<>(arrayList);
    }

    @Override
    public void toParcel(Set<Amoeba> value, Parcel dest) {
        final ArrayList<Amoeba> arrayList = new ArrayList<>(value);
        dest.writeTypedList(arrayList);
    }
}

我需要传递给 readTypedArray 的 CREATOR 在 AutoValue_Amoeba 中声明。

我的错误在哪里?对auto-value-parcel的误解?

【问题讨论】:

    标签: android parcelable auto-value


    【解决方案1】:

    AutoValue:Parcel 扩展无法处理集合,但如果您将属性转换为 List,则无需自定义适配器即可开箱即用。如果您想将其视为Set,您可以这样做。请记住,您可能还想缓存Set

    @AutoValue
    public abstract class Xenarchaeota implements Parcelable {
    
        abstract List<Amoeba> amoebaList();
        public Set<Amoeba> amoebas() {
            return new TreeSet(amoebaList());
        }
    
        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();
        }
    }
    

    【讨论】:

    • 感谢您查看此内容。我正在将我的 Set 转换为适配器中的列表,但是我认为我必须使用类型化列表并传递类型 CREATOR。
    • 在不使用 TypedList 的情况下,更多地将 Amoeba 保存在 Parcelable 中并不是 Set“问题”。我认为不使用 TypedList 会增加 Parcelable 的大小,并且与 Parceling TypedList 相比性能较差。
    • 如果您将其设为List,它将通过Parcel#writeValue(val) 进行往返,因此对于一些额外的方法调用和类型检查会有一个性能命中。我认为这是一个小打击,因为这是序列化,它涉及其他性能问题(IPC 等),但这取决于你。另一种选择是将它设为一个数组,并像这里详述的那样包装它。 Parcelable[] 直接写入,但读取需要读取类的类加载器(它使用反射加载 Creator)。
    【解决方案2】:

    我相信我已经确定了如下解决方案:-

    目前是auto-value-parcel

    com.ryanharter.auto.value.parcel.AutoValueParcelExtension
    

    有一个方法叫generateCreator:-

    FieldSpec generateCreator(ProcessingEnvironment env, TypeName autoValueType, List<Property> properties, TypeName type, Map<TypeMirror, FieldSpec> typeAdapters) {
            ClassName creator = ClassName.bestGuess("android.os.Parcelable.Creator");
    
            TypeName creatorOfClass = ParameterizedTypeName.get(creator, type);
            ...
            ...
    

    此方法生成类似于此的Parcelable CREATOR

    public static final Parcelable.Creator<AutoValue_Amoeba> CREATOR = new Parcelable.Creator<AutoValue_Amoeba>() {
        @Override
        public AutoValue_Amoeba createFromParcel(Parcel in) {
          return new AutoValue_Amoeba(
              in.readString()
          );
        }
        @Override
        public AutoValue_Amoeba[] newArray(int size) {
          return new AutoValue_Amoeba[size];
        }
      };
    

    如果generateCreator方法改变如下:-

    FieldSpec generateCreator(ProcessingEnvironment env, TypeName autoValueType, List<Property> properties, TypeName type, Map<TypeMirror, FieldSpec> typeAdapters) {
            ClassName creator = ClassName.bestGuess("android.os.Parcelable.Creator");
    
            TypeName creatorOfClass = ParameterizedTypeName.get(creator, autoValueType);  // CHANGE MADE HERE!!! swap type with autoValueType
            ...
            ...
    

    然后此方法将生成一个类似于此的Parcelable CREATOR

    public static final Parcelable.Creator<Amoeba> CREATOR = new Parcelable.Creator<Amoeba>() {
        @Override
        public AutoValue_Amoeba createFromParcel(Parcel in) {
          return new AutoValue_Amoeba(
              in.readString()
          );
        }
        @Override
        public AutoValue_Amoeba[] newArray(int size) {
          return new AutoValue_Amoeba[size];
        }
      };
    

    这个 CREATOR 现在允许 TypeAdapter 使用 CREATOR,如下所示

    class AmoebaTypeAdapter implements TypeAdapter<Set<Amoeba>> {
    
        @Override
        public Set<Amoeba> fromParcel(Parcel in) {
            final List<Amoeba> arrayList = new ArrayList<>();
            in.readTypedList(arrayList, AutoValue_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);
        }
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2012-05-29
    • 2021-05-14
    相关资源
    最近更新 更多