片段中,使用Parcelable实现还原包含另一个对象列表的对象

时间:2019-01-03 16:15:51

标签: android android-fragments parcelable

我有一个Car类的实现Parcelable

public class Car implements Parcelable {
    private long id;
    private String model;

    public Car(long id, String model) {
       this.id = id;
       this.model = model;
    }

    public String getModel() {
        return model;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(this.id);
        dest.writeString(this.model);

    }

    private Car(Parcel in) {
        this.id = in.readLong();
        this.model = in.readString();
    }

    public static final Creator<Car> CREATOR = new Creator<Car>() {
        @Override
        public Car createFromParcel(Parcel source) {
            return new Car(source);
        }

        @Override
        public Car[] newArray(int size) {
            return new Car[size];
        }
    };
}

然后,我有一个Store类,其中包含汽车列表,它也实现了Parcelable

public class Store implements Parcelable {
   private List<Car> carList = new ArrayList<>();

   public List<Car> getCarList() {
        return carList;
    }
   public void setCarList(List<Car> cars) {
        carList = cars;
   }

   @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
       dest.writeTypedList(this.carList);
    }

    private Store(Parcel in) {
      in.readTypedList(carList, Car.CREATOR);
    }

    public static final Creator<Store> CREATOR = new Creator<Store>() {
        @Override
        public Store createFromParcel(Parcel source) {
            return new Store(source);
        }

        @Override
        public Store[] newArray(int size) {
            return new Store[size];
        }
    };
}

在一个片段中,我尝试还原名为Store的{​​{1}}实例,包括其中的汽车列表:

myStore

class MyFragment extends Fragment { private Store myStore; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null && savedInstanceState.containsKey(MY_STORE)) { myStore = savedInstanceState.getParcelable(MY_STORE); // PROBLEM IS HERE: // when runtime hit here, the restored myStore contains one car but has id with weird long value and null in model field. WHY? } else { // initialize myStore with car list (only one car) Car myCar = new Car(1, "BMW X1"); List<Car> cars = new ArrayList<>(); cars.add(myCar); myStore = new Store(); myStore.setCarList(cars); } } @Override public void onSaveInstanceState(@NonNull Bundle outState) { if(myStore != null) { outState.putParcelable(MY_STORE, myStore); } super.onSaveInstanceState(outState); } } 中,代码尝试在MyFragment中恢复myStore时出现问题。在运行时,已还原的onCreate()确实在列表中包含一辆汽车,但是该列表中的汽车ID带有奇怪的长值(例如myStore)和28429333427126393中的null领域。为什么?我做错了什么?如何还原包含另一个对象列表的对象?

1 个答案:

答案 0 :(得分:0)

当您的carList实例为空时,通常会发生此问题,因此您在parcelable中编写了一个空对象并尝试从中读取。

其中一个选项是在列表为null时初始化列表,然后将其写成包裹。在这种情况下,您的列表在还原后将始终具有引用,而这可能并不是您想要的。

另一种方法是在将列表写入parcelable之前写一个字节值,表明您的列表为空,或者您应该从中获取一些值。对于这种情况,我使用this helper class来解决我自己的问题。根据我的需要,我进行了一些改进。如果您想使用它,这是我的版本:

public class ParcelableUtils {
    public static void write(Parcel dest, String string) {
        dest.writeByte((byte) (string == null ? 0 : 1));
        if (string != null) {
            dest.writeString(string);
        }
    }

    public static String readString(Parcel source) {
        if (source.readByte() == 1) {
            return source.readString();
        }
        return null;
    }

    public static void write(Parcel dest, Parcelable parcelable, int flags) {
        dest.writeByte((byte) (parcelable == null ? 0 : 1));
        if (parcelable != null) {
            dest.writeParcelable(parcelable, flags);
        }
    }

    public static <T extends Parcelable> T readParcelable(Parcel source) {
        if (source.readByte() == 1) {
            return source.readParcelable(null);
        }
        return null;
    }

    public static <T extends Parcelable> T readParcelable(Parcel source, Class objectClass) {
        if (source.readByte() == 1) {
            return source.readParcelable(objectClass.getClassLoader());
        }
        return null;
    }

    public static void write(Parcel dest, Map<String, String> strings) {
        if (strings == null) {
            dest.writeInt(-1);
        }
        {
            dest.writeInt(strings.keySet().size());
            for (String key : strings.keySet()) {
                dest.writeString(key);
                dest.writeString(strings.get(key));
            }
        }
    }

    public static Map<String, String> readStringMap(Parcel source) {
        int numKeys = source.readInt();
        if (numKeys == -1) {
            return null;
        }
        HashMap<String, String> map = new HashMap<String, String>();
        for (int i = 0; i < numKeys; i++) {
            String key = source.readString();
            String value = source.readString();
            map.put(key, value);
        }
        return map;
    }

    public static <T extends Parcelable> void write(Parcel dest, Map<String, T> objects, int flags) {
        if (objects == null) {
            dest.writeInt(-1);
        } else {
            dest.writeInt(objects.keySet().size());
            for (String key : objects.keySet()) {
                dest.writeString(key);
                dest.writeParcelable(objects.get(key), flags);
            }
        }
    }

    public static <T extends Parcelable> Map<String, T> readParcelableMap(Parcel source) {
        int numKeys = source.readInt();
        if (numKeys == -1) {
            return null;
        }
        HashMap<String, T> map = new HashMap<String, T>();
        for (int i = 0; i < numKeys; i++) {
            String key = source.readString();
            T value = source.readParcelable(null);
            map.put(key, value);
        }
        return map;
    }

    public static void write(Parcel dest, URL url) {
        dest.writeString(url.toExternalForm());
    }

    public static URL readURL(Parcel source) {
        try {
            return new URL(source.readString());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void write(Parcel dest, Date date) {
        dest.writeByte((byte) (date == null ? 0 : 1));
        if (date != null) {
            dest.writeLong(date.getTime());
        }
    }

    public static Date readDate(Parcel source) {
        if (source.readByte() == 1) {
            return new Date(source.readLong());
        }
        return null;
    }

    public static <T extends java.lang.Enum<T>> void write(Parcel dest, java.lang.Enum<T> enu) {
        if (enu == null) {
            dest.writeString("");
        } else {
            dest.writeString(enu.name());
        }
    }

    public static <T extends java.lang.Enum<T>> T readEnum(Parcel dest, Class<T> clazz) {
        String name = dest.readString();
        if ("".equals(name)) {
            return null;
        }
        return java.lang.Enum.valueOf(clazz, name);
    }

    public static void write(Parcel dest, boolean bool) {
        dest.writeByte((byte) (bool ? 1 : 0));
    }

    public static boolean readBoolean(Parcel source) {
        return source.readByte() == 1;
    }

    public static <T extends Parcelable> void write(Parcel dest,
                                                    List<T> fields, int flags) {
        if (fields == null) {
            dest.writeInt(-1);
        } else {
            dest.writeInt(fields.size());
            for (T field : fields) {
                dest.writeParcelable(field, flags);
            }
        }
    }

    @SuppressWarnings("unchecked")
    public static <T extends Parcelable> List<T> readParcelableList(
            Parcel source) {
        int size = source.readInt();
        if (size == -1) {
            return null;
        }
        ArrayList<T> list = new ArrayList<T>();
        for (int i = 0; i < size; i++) {
            list.add((T) source.readParcelable(null));
        }
        return list;
    }
}

希望有帮助。