实现 Parcelable 接口时如何读/写布尔值?

Posted

技术标签:

【中文标题】实现 Parcelable 接口时如何读/写布尔值?【英文标题】:How to read/write a boolean when implementing the Parcelable interface? 【发布时间】:2011-09-06 06:38:14 【问题描述】:

我正在尝试创建 ArrayList Parcelable 以便将自定义对象列表传递给活动。我开始编写一个扩展ArrayList<myObject> 并实现ParcelablemyObjectList 类。

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

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

【问题讨论】:

因为我所做的关于在活动之间传递对象的所有阅读都预先确定了使用 parcelable 而不是 serialisable。 @MisterSquonk 您不应该使用Serializable 接口进行交互通信。速度很慢。 @grunk:好的,这很公平,但在 Intent.putExtra(String name, Serializable value) 在文档中被标记为已弃用之前,如果它能让生活更轻松,我会很乐意继续使用它为了我。只是一个想法。 @Octavian:但这取决于每个案例研究并且是相对的。 在我看来,android的架构师团队很懒!!! whereis boolean!!!!!!!!! 【参考方案1】:

这就是我的做法......

writeToParcel:

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

从包裹中读取:

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

【讨论】:

没有理由使用字节而不是 int。 byte 由于强制转换而更加冗长:dest.writeInt(myBoolean ? 1 : 0); 为什么@SiPlus 的评论获得了如此多的支持? 1 和 0 都没有被“加载”。这完全没有区别。 Java 从什么时候开始成为弱类型语言? @sotrh 写入一个字节只是写入一个 int:/** * Write a byte value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeByte(byte val) writeInt(val); @Dallas 是来自文档吗?如果是这样,请忽略我的评论。 api 有一个写着writeByte 的函数似乎是不诚实的,但实际上写的是一个 int。 @sotrh 是源代码的复制粘贴。打开 android.os.Parcel 源码自己看看。【参考方案2】:

您也可以使用writeValue 方法。在我看来,这是最直接的解决方案。

dst.writeValue( myBool );

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

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

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

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

【讨论】:

android source 显示“引擎盖下”部分(l. 1219)。虽然效率稍低(因为方法调用和开关),但这个方法读起来更直接。 这里写的代码不会编译。 readValue 需要一个类加载器,但布尔值不需要它。它应该是“boolean myBool = (Boolean) source.readValue(null);”不知道自己在做什么并拒绝我对此答案的编辑的审稿人:@hemang,jeeped,DavidRR。 @miguel 是的,已修复 :) 这个简单的任务最好不要乱用类加载器。【参考方案3】:

你这样声明

 private boolean isSelectionRight;

 out.writeInt(isSelectionRight ? 1 : 0);

阅读

isSelectionRight  = in.readInt() != 0;

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

【讨论】:

这会导致错误,类型不兼容,找到所需的布尔值?【参考方案4】:

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


...

【讨论】:

这很方便:)【参考方案5】:

我通常将它们放在一个数组中并调用writeBooleanArrayreadBooleanArray

如果你需要打包一个布尔值,你可以这样做:

parcel.writeBooleanArray(new boolean[] myBool);

【讨论】:

当您需要打包几个布尔值时,您是否遇到过问题...我有。你能帮我吗>?***.com/questions/13463727/…。谢谢。【参考方案6】:
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read

【讨论】:

【参考方案7】:

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

向 Parcel 添加方法

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 我解决了这个问题。为了工作,添加的方法必须在companion object【参考方案8】:

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

只需转到文件->设置->插件->浏览存储库并搜索parcelable。查看图片

它会自动创建 Parcelable。

还有一个网站也可以做到这一点。 http://www.parcelabler.com/

【讨论】:

【参考方案9】:

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

【讨论】:

+1。的确,将值保存在一个字节中会更有效。你介意我编辑我的问题来代表你的想法吗? 你可以,但你写的不是我的意思。它会起作用,但不是最有效的。您可以使用掩码和布尔代数将 8 个布尔值打包成一个字节 在大多数情况下我同意你的观点,但是我确实有一些情况会不时出现,我需要布尔值可以处理的三个状态。例如可选的是/否问题。我需要 null 来知道是否明确指定了布尔值。 没有理由使用byte over int,因为Parcel的writeByte()方法直接调用writeInt()【参考方案10】:

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

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

您必须将值存储为字符串或字节。如果你要一个字符串,那么你将不得不使用 String 类的静态方法 valueOf() 来解析布尔值。它不如将它保存在一个字节中那么有效。

String.valueOf(theBoolean);

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

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

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

【讨论】:

绝对没有理由使用字符串。没有理由在 int 上使用字节,因为 Parcel 的 writeByte() 方法直接调用 writeInt()。转换逻辑过于冗长。只需执行writeInt(boolean ? 1 : 0)boolean = readInt() != 0【参考方案11】:

如果你想自己做的话,其他人已经完美地回答了这个问题。

如果您喜欢封装或隐藏大部分低级打包代码,您可以考虑使用some of the code I wrote some time ago for simplifying handling of parcelables.

写入包裹很简单:

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()【参考方案12】:

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

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


private PackageInfo(Parcel source) 
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...

【讨论】:

【参考方案13】:

对于 API 29 及以上我们可以使用

writeToParcel:

dest.writeBoolean(booleanFlag);

readFromParcel:

booleanFlag = in.readBoolean()

或者我们可以使用

writeToParcel:

dest.writeByte((byte) (booleanFlag ? 1 : 0));

从包裹中读取:

booleanFlag = in.readByte() != 0;

【讨论】:

以上是关于实现 Parcelable 接口时如何读/写布尔值?的主要内容,如果未能解决你的问题,请参考以下文章

为只定义读的接口实现读/写字段

如何写Parcelable()一个实现Serializable的类型的字段

使用 Parcelable 接口时如何序列化空值

Android中Intent传递对象的两种方法(Serializable,Parcelable)

从 Android 中的对象实现 Serializable 和 Parcelable 接口 - 冲突

Kotlin 快速实现 Parcelable 接口