我有一个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
领域。为什么?我做错了什么?如何还原包含另一个对象列表的对象?
答案 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;
}
}
希望有帮助。