实施Parcelable接口时如何读取/写入布尔值?


404

我试图使一个ArrayList Parcelable自定义对象列表传递给活动。我开始写一个myObjectList扩展ArrayList<myObject>和实现的类Parcelable

的某些属性MyObject是,booleanParcel没有任何方法read/writeBoolean

处理此问题的最佳方法是什么?


3
因为我所做的所有关于在活动之间传递对象的阅读都使可打包而不是可序列化的使用变得简单。
2011年

10
@MisterSquonk您不应使用该Serializable界面进行交互性通信。太慢了
Octavian A. Damiean 2011年

1
@grunk:好的,这很公平,但是在文档中将Intent.putExtra(String name,Serializable value)标记为已弃用之前,如果它使我的生活变得更轻松,我将很高兴继续使用它。只是一个想法。
Squonk 2011年

3
@Octavian:但这取决于个案研究,并且是相对的。
Squonk 2011年

2
在我看来,android的架构师团队很懒!布尔值在哪里!!!!!!!!
Mateus

Answers:


942

这是我的做法...

writeToParcel:

dest.writeByte((byte) (myBoolean ? 1 : 0));     //if myBoolean == true, byte == 1

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0

38
没有理由在int上使用字节。字节由于强制转换而更加冗长:dest.writeInt(myBoolean?1:0);
miguel

为什么@SiPlus评论获得如此多的赞誉?1和0都不会被“加载”。绝对没有区别。既然Java什么时候是一种弱类型的语言?
2015年

13
@sotrh写一个字节只是写一个整数:/** * Write a byte value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeByte(byte val) { writeInt(val); }
达拉斯

3
@Dallas是来自文档吗?如果是这样,则无视我的评论。对于api来说,似乎似乎毫无意义writeByte,但实际上写了一个int。
sotrh

1
@sotrh是源代码中的复制粘贴。打开android.os.Parcel源代码,自己看看。
Yaroslav Mytkalyk '16

66

您也可以使用writeValue方法。我认为这是最直接的解决方案。

dst.writeValue( myBool );

之后,您可以通过简单的强制转换为轻松地检索它Boolean

boolean myBool = (Boolean) source.readValue( null );

在底层,Android框架会将其作为整数处理:

writeInt( (Boolean) v ? 1 : 0 );

android源代码显示“引擎盖下”部分(1219年)。尽管效率略低(由于方法调用和切换),但此方法的读取方式更直接一些。
desseim 2014年

6
此处编写的代码将无法编译。readValue需要一个类加载器,但布尔型则不需要。它应显示为“ boolean myBool =(Boolean)source.readValue(null);” 不知道自己在做什么的审阅者拒绝了我对此答案的编辑:@hemang,吉普,DavidRR。
miguel 2015年

1
@miguel没错,将其修复:)
Taig 2015年

15

你这样声明

 private boolean isSelectionRight;

 out.writeInt(isSelectionRight ? 1 : 0);

isSelectionRight  = (in.readInt() == 0) ? false : true;

布尔类型需要转换为Parcel支持的格式,因此我们可以将其转换为int。


这会导致错误,类型不兼容,需要布尔值int吗?
Paul Okeke

12

AndroidStudio(使用2.3 atm),在您的类上实现了Parcelable之后,您只需将鼠标指针悬停在您的类名称上,它会要求您添加parcelable实现:

在此处输入图片说明

它从这四个字段生成以下内容:

public class YourClass implements Parcelable{

String someString;
int someInt;
boolean someBoolean;
List<String> someList;

protected YourClass(Parcel in) {
    someString = in.readString();
    someInt = in.readInt();
    someBoolean = in.readByte() != 0;
    someList = in.createStringArrayList();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(someString);
    dest.writeInt(someInt);
    dest.writeByte((byte) (someBoolean ? 1 : 0));
    dest.writeStringList(someList);
}

...

这很方便:)
Dino Tw

8

我通常让他们在一个数组和呼叫writeBooleanArrayreadBooleanArray

如果您需要打包一个布尔值,则可以执行以下操作:

parcel.writeBooleanArray(new boolean[] {myBool});

当您需要打包几个布尔值时,您是否遇到过问题...我有。你能帮我吗?stackoverflow.com/questions/13463727/…。谢谢。
罗杰·阿里恩

8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read

5

如果您使用的是Android Studio,我建议您实现Parcelable的最简单方法。

只需转到File-> Settings-> Plugins-> Browse Repository并搜索可打包文件。

在此处输入图片说明 它将自动创建Parcelable。

也有一个网络管理员可以这样做。http://www.parcelabler.com/


4

Kotlin中的简短实现,可空支持:

向包裹添加方法

fun Parcel.writeBoolean(flag: Boolean?) {
    when(flag) {
        true -> writeInt(1)
        false -> writeInt(0)
        else -> writeInt(-1)
    }
}

fun Parcel.readBoolean(): Boolean? {
    return when(readInt()) {
        1 -> true
        0 -> false
        else -> null
    }
}

并使用它:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false

@AliKazi您无法在Java中使用支持可选类型的1行语句中执行此操作。您应该坚持3个州。我认为您忘记了null。
帕维尔·肖罗霍夫

@ comm1x,IDE不喜欢此解决方案。在调用超类构造函数之前,无法访问“ readBoolean”。
亚当·赫维兹

@ comm1x我解决了这个问题。为了工作,添加的方法必须在伴随对象内
Adam Hurwitz

3

您可以使用掩码和移位将布尔值打包为一个字节。那将是最有效的方法,并且可能是他们希望您这样做的方法。


+1。的确,将值保存在一个字节中会更有效。您介意编辑我的问题以代表您的想法吗?
Octavian A. Damiean 2011年

可以,但是您写的不是我真正的意思。它会工作,但不是最有效的。您可以使用掩码和布尔代数将8个布尔值打包为一个字节
Fleetway76,2011年

在大多数情况下,我都同意您的观点,但是我确实有一些情况会不时地出现,在这种情况下,我需要布尔工作的三种状态。例如可选的是/否问题。我需要null才能知道是否已明确指定布尔值。
乍得·高尔欣2011年

没有理由使用byte over int,因为包裹的writeByte()方法直接调用writeInt()
Yaroslav Mytkalyk '16

3

在这里很难确定真正的问题。我想这是实现Parcelable接口时如何处理布尔值的方法。

MyObject的某些属性是boolean,但是Parcel没有任何方法read / writeBoolean。

您将必须将值存储为字符串或字节。如果要查找字符串,则必须使用String该类的静态方法valueOf()来解析布尔值。它不如将其保存在一个字节内有效。

String.valueOf(theBoolean);

如果需要一个字节,则必须自己实现转换逻辑。

byte convBool = -1;
if (theBoolean) {
    convBool = 1;
} else {
    convBool = 0;
}

解组Parcel对象时,必须注意转换为原始类型。


绝对没有理由使用String。由于Parcel的writeByte()方法直接调用,因此没有理由使用byte over int writeInt()。转换逻辑太冗长。只是做writeInt(boolean ? 1 : 0)boolean = readInt() != 0
雅罗斯拉夫Mytkalyk

1

如果您想自己做,其他人已经很好地回答了这个问题。

如果您希望封装或隐藏大多数低级包裹代码,则可以考虑使用我前一段时间编写的一些代码,以简化包裹的处理。

写包裹很容易:

parcelValues(dest, name, maxSpeed, weight, wheels, color, isDriving);

例如,其中color是一个枚举,而isDriving是一个布尔值。

从包裹中读取也不难:

color = (CarColor)unparcelValue(CarColor.class.getClassLoader());
isDriving = (Boolean)unparcelValue();

只需看看我添加到项目中的“ ParceldroidExample”即可。

最后,它还使CREATOR初始化程序简短:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);

谢谢你.class.getClassLoader()
CoolMind

0

Android(AOSP)源代码中有很多示例。例如,PackageInfoclass有一个布尔成员requiredForAllUsers,它按如下方式序列化:

public void writeToParcel(Parcel dest, int parcelableFlags) {
    ...
    dest.writeInt(requiredForAllUsers ? 1 : 0);
    ...
}

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.