实现 Parcelable 时使用 Float 而不是 float(Primitive 类型)
Using Float instead of float (Primitive type) when implementing Parcelable
要求:判断price
是否为空。由于无法检查原始浮点数据类型是否为 null,因为它始终为 0.0,因此我选择不使用 Float
,因为它可以检查是否为 null。
public class QOptions implements Parcelable {
public String text;
public Float price;
}
protected QOptions(Parcel in) {
text = in.readString();
unit_price = in.readFloat();
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(this.text);
parcel.writeFloat(this.price);
}
但是,由于 class 也实现了 Parcelable
,因此 writeToParcel
崩溃并出现以下异常:
Attempt to invoke virtual method 'float java.lang.Float.floatValue()' on a null object reference
异常指向这一行:
parcel.writeFloat(this.price);
如何将 Float
数据类型与 writeToParcel 一起使用而不导致异常?还是有更好的方法来完成我的要求?如果价格为空,我只需要价格为空。
您可以按照以下方式处理。
@Override
public void writeToParcel(Parcel dest, int flags) {
if (price == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeFloat(price);
}
}
读取浮点数的值 -
unit_price = in.readByte() == 0x00 ? null : in.readFloat();
小数类型有许多特殊值:NaN、负无穷大和正无穷大。您可以使用这些值来表示 null
:
if (price == null) {
parcel.writeFloat(Float.NaN);
} else {
parcel.writeFloat(price);
}
阅读时:
float p = parcel.readFloat();
if (Float.isNaN(p)) {
price = null;
} else {
price = p;
}
NaN 的意思是 "not a number",所以它有点适合序列化事物的主题。
与@Kapil G 提供的解决方案不同,此方法不会为可空性标志浪费额外的 4 个字节(出于性能原因,对 writeByte()
的每次调用实际上都将整个 int
存储在 Parcal 中)。
对于打包Float
这两个方法调用是安全的:
dest.writeValue(price);
in.readValue(null);
要打包任何可打包类型,您可以使用此:
SomeType value; // ...
dest.writeValue(value);
in.readValue(SomeType.class.getClassLoader());
可以找到可打包类型列表 in Parcel
docs。
优点
- 每次读写一行。
- 您不必担心在打包和解包时手动区分
null
和 float
。它已在内部为您完成。
- 可以表达 NaN 和无穷大。
工作原理
这里是Parcel
源代码的相关部分:
public class Parcel {
private static final int VAL_NULL = -1;
private static final int VAL_FLOAT = 7;
public final void writeValue(Object v) {
if (v == null) {
writeInt(VAL_NULL);
} else if (v instanceof Float) {
writeInt(VAL_FLOAT);
writeFloat((Float) v);
} // ...
}
public final Object readValue(ClassLoader loader) {
int type = readInt();
switch (type) {
case VAL_NULL:
return null;
case VAL_FLOAT:
return readFloat();
// ...
}
}
}
请注意,对于 Float
(和其他盒装原语),loader
参数未使用,因此您可以传递 null
.
要求:判断price
是否为空。由于无法检查原始浮点数据类型是否为 null,因为它始终为 0.0,因此我选择不使用 Float
,因为它可以检查是否为 null。
public class QOptions implements Parcelable {
public String text;
public Float price;
}
protected QOptions(Parcel in) {
text = in.readString();
unit_price = in.readFloat();
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(this.text);
parcel.writeFloat(this.price);
}
但是,由于 class 也实现了 Parcelable
,因此 writeToParcel
崩溃并出现以下异常:
Attempt to invoke virtual method 'float java.lang.Float.floatValue()' on a null object reference
异常指向这一行:
parcel.writeFloat(this.price);
如何将 Float
数据类型与 writeToParcel 一起使用而不导致异常?还是有更好的方法来完成我的要求?如果价格为空,我只需要价格为空。
您可以按照以下方式处理。
@Override
public void writeToParcel(Parcel dest, int flags) {
if (price == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeFloat(price);
}
}
读取浮点数的值 -
unit_price = in.readByte() == 0x00 ? null : in.readFloat();
小数类型有许多特殊值:NaN、负无穷大和正无穷大。您可以使用这些值来表示 null
:
if (price == null) {
parcel.writeFloat(Float.NaN);
} else {
parcel.writeFloat(price);
}
阅读时:
float p = parcel.readFloat();
if (Float.isNaN(p)) {
price = null;
} else {
price = p;
}
NaN 的意思是 "not a number",所以它有点适合序列化事物的主题。
与@Kapil G 提供的解决方案不同,此方法不会为可空性标志浪费额外的 4 个字节(出于性能原因,对 writeByte()
的每次调用实际上都将整个 int
存储在 Parcal 中)。
对于打包Float
这两个方法调用是安全的:
dest.writeValue(price);
in.readValue(null);
要打包任何可打包类型,您可以使用此:
SomeType value; // ...
dest.writeValue(value);
in.readValue(SomeType.class.getClassLoader());
可以找到可打包类型列表 in Parcel
docs。
优点
- 每次读写一行。
- 您不必担心在打包和解包时手动区分
null
和float
。它已在内部为您完成。 - 可以表达 NaN 和无穷大。
工作原理
这里是Parcel
源代码的相关部分:
public class Parcel {
private static final int VAL_NULL = -1;
private static final int VAL_FLOAT = 7;
public final void writeValue(Object v) {
if (v == null) {
writeInt(VAL_NULL);
} else if (v instanceof Float) {
writeInt(VAL_FLOAT);
writeFloat((Float) v);
} // ...
}
public final Object readValue(ClassLoader loader) {
int type = readInt();
switch (type) {
case VAL_NULL:
return null;
case VAL_FLOAT:
return readFloat();
// ...
}
}
}
请注意,对于 Float
(和其他盒装原语),loader
参数未使用,因此您可以传递 null
.