自动值包装适配器能处理另一个自动值类的类型集吗?

8

我正在研究auto-value及其扩展,即在我的Android应用程序中使用的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?

2个回答

3

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转换为List,但是我认为我必须使用类型化的列表并传递类型CREATOR。 - Hector
这并不是 Set“问题”,而是在不使用 TypedList 的情况下在 Parcelable 中保存 Amoeba。我认为,通过不使用 TypedList,Parcelable 的大小会增加,并且与分别集合化 TypedList 的性能相比会表现更差。 - Hector
1
如果将其设置为List,它将通过Parcel#writeValue(val)进行往返传输,因此会有一些额外的方法调用和类型检查的性能损失。我认为这只是一个小问题,因为这是序列化,涉及其他性能问题(IPC等),但这取决于您。另一个选择是将其设置为数组,并像此处详细说明的那样进行包装。Parcelable[]直接被写入,但读取需要要读取类的类加载器(它使用反射来加载Creator)。 - rharter

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

我们早期就研究过这个问题,并在此处进行了讨论:https://github.com/rharter/auto-value-parcel/issues/101 - rharter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接