417

I'm trying to make an ArrayList Parcelable in order to pass to an activity a list of custom object. I start writing a myObjectList class which extends ArrayList<myObject> and implement Parcelable.

Some attributes of MyObject are boolean but Parcel don't have any method read/writeBoolean.

What is the best way to handle this?

Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
grunk
  • 14,718
  • 15
  • 67
  • 108
  • @grunk: ArrayList already implements Serializable. Why don't you just make your custom objects Serializable? – Squonk Jun 01 '11 at 12:49
  • 3
    Because all the reading i have done about passing object between activities preconise the use of parcelable instead of serialisable. – grunk Jun 01 '11 at 13:01
  • 10
    @MisterSquonk You should not use the `Serializable` interface for inter-activity communication. It is slow. – Octavian Helm Jun 01 '11 at 13:05
  • 1
    @grunk: OK, that's fair enough but until Intent.putExtra(String name, Serializable value) is marked as deprecated in the docs, I'll be happy to continue using it if it makes life easier for me. Just a thought. – Squonk Jun 01 '11 at 13:06
  • 3
    @Octavian: But that depends on a per-case study and is relative. – Squonk Jun 01 '11 at 13:07
  • @MisterSquonk You should read up what happens when using `Serializable`. Also any class extending `ArrayList` will be `Serializable` anyway. – Octavian Helm Jun 01 '11 at 13:08
  • Does your ArrayList hold booleans? – Octavian Helm Jun 01 '11 at 13:13
  • 1
    @Octavian: Yes, I understand the different mechanisms involved and the potential inefficiency of Serializing with Android. However, my original comment asked 'why not?' and as this is case-dependent it may well be that with small serializable objects, the performance difference is sufficiently negligible to out-weigh the extra complexity of using Parcelable. Also, my original comment points out that ArrayList is serializable but in the case of ArrayList then 'E' may not be but can often be made to be very easily. The OP didn't go into detail about their object so it was a simple question. – Squonk Jun 01 '11 at 13:21
  • Actually there are writeBooleanArray(boolean[]), readBooleanArray(boolean[]), createBooleanArray(). But i have issues with them. http://stackoverflow.com/questions/13463727/readbooleanarray-throws-runtimeexceptionbad-array-lengths. – Roger Alien Nov 23 '12 at 22:05
  • 2
    in my oppinion, the architect team of android is lazy!!! whereis boolean!!!!!!!! – Mateus Mar 08 '13 at 12:30
  • Complain here: https://code.google.com/p/android/issues/detail?id=5973 – marcinj Aug 24 '16 at 08:51
  • 1
    In __API 29__ class `Parcel` finally has `writeBoolean()` method (https://developer.android.com/reference/android/os/Parcel#writeBoolean(boolean)) – Alex Semeniuk Aug 27 '19 at 09:07
  • It just took 10 years :D – grunk Sep 02 '19 at 08:56

14 Answers14

964

Here's how I'd do it...

writeToParcel:

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

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0
b_yng
  • 14,136
  • 6
  • 32
  • 35
  • 40
    No reason to use byte over int. byte is more verbose because of the cast: dest.writeInt(myBoolean ? 1 : 0); – miguel Jan 17 '15 at 02:31
  • Why did @SiPlus comment get so many upvotes? Neither 1, nor 0 is "loaded" at all. It makes absolutely no difference. And since when is Java a weakly-typed language? – noone Jun 17 '15 at 06:45
  • @miguel nope - you still **have to cast** – martyglaubitz Jul 14 '15 at 12:49
  • @miguel a byte is smaller than an int (a 32-bit int is 4 bytes), so it makes more sense to use a byte if you want to maximize parcel compression. – sotrh Oct 08 '15 at 21:40
  • 14
    @sotrh writing a byte just writes an 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 Oct 13 '15 at 02:14
  • 3
    @Dallas is that from the documentation? If so then disregard my comment. Seems disingenuous for the api to have a function that says `writeByte`, but actually writes an int. – sotrh Oct 13 '15 at 02:21
  • 1
    @sotrh that is a copy-paste from a source code. Open android.os.Parcel source and see for yourself. – Yaroslav Mytkalyk Jan 05 '16 at 10:19
  • @sotrh This is an implementation detail and is a subject to change. I guess, that's why they encourage to never use Parcelable to persist data. Different implementation will break on reading from Parcel. – Varvara Kalinina May 28 '19 at 14:37
  • Just for someone who might be trying similar thing in Kotlin.. To write: parcel.writeByte((if (yourBooleanVariable) 1 else 0).toByte()) To read, I had to do following because apparently you cannot directly compare with != in kotlin yourBooleanVariable =when(parcel.readByte()) { 0.toByte() -> false else -> true} – AbdulMueed Sep 30 '20 at 04:09
70

You could also make use of the writeValue method. In my opinion that's the most straightforward solution.

dst.writeValue( myBool );

Afterwards you can easily retrieve it with a simple cast to Boolean:

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

Under the hood the Android Framework will handle it as an integer:

writeInt( (Boolean) v ? 1 : 0 );
Taig
  • 6,718
  • 4
  • 44
  • 65
  • [android source](https://android.googlesource.com/platform/frameworks/base/+/ac5a0828c14eea59f2ffda85432ad1977d3e1ce0/core/java/android/os/Parcel.java) showing the "under the hood" part (l. 1219). Though a tiny bit less efficient (because of the method call and the switch) this method reads a bit more straightforward. – desseim Feb 12 '14 at 18:08
  • 6
    The code as written here will not compile. readValue requires a classloader but it's not needed for Booleans. It should read "boolean myBool = (Boolean) source.readValue(null);" Reviewers that have no idea what they're doing and rejected my edit to this answer: @hemang, jeeped, DavidRR. – miguel Jan 27 '15 at 00:28
  • 1
    @miguel That's true, fixed it :) – Taig Jan 27 '15 at 01:35
  • It's better to not mess with classLoaders for this simple task. – JohnyTex Jan 15 '21 at 08:47
21

you declare like this

 private boolean isSelectionRight;

write

 out.writeInt(isSelectionRight ? 1 : 0);

read

isSelectionRight  = in.readInt() != 0;

boolean type needs to be converted to something that Parcel supports and so we can convert it to int.

JohnyTex
  • 3,323
  • 5
  • 29
  • 52
Shaista Naaz
  • 8,281
  • 9
  • 37
  • 50
16

AndroidStudio (using 2.3 atm), after implementing Parcelable on your class, you can simply hold your mouse pointer over your class name and it asks you to add the parcelable implementation:

enter image description here

From the four fields, it generates the following:

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

...
Henk-Martijn
  • 2,024
  • 21
  • 25
8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read
Meghna
  • 539
  • 4
  • 14
8

I normally have them in an array and call writeBooleanArray and readBooleanArray

If it's a single boolean you need to pack, you could do this:

parcel.writeBooleanArray(new boolean[] {myBool});
Geobits
  • 22,218
  • 6
  • 59
  • 103
  • Have you ever faced problem when you need to parcel few booleans... i have. Could You please help me> ?http://stackoverflow.com/questions/13463727/readbooleanarray-throws-runtimeexceptionbad-array-lengths. Thanks. – Roger Alien Nov 23 '12 at 22:04
6

Short and simple implementation in Kotlin, with nullable support:

Add methods to 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
    }
}

And use it:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false
Pavel Shorokhov
  • 4,485
  • 1
  • 35
  • 44
  • @AliKazi you can't do this in 1 line statement in Java with support optional types. You should persist 3 states. I think you forget about null. – Pavel Shorokhov Apr 17 '18 at 23:22
  • @comm1x, The IDE does not like this solution. `Cannot access "readBoolean" before superclass constructor has been called. – AdamHurwitz Sep 25 '18 at 18:43
  • @comm1x I resolved the issue. In order to work the added methods must be within the [**companion object**](https://gist.github.com/AdamSHurwitz/a988681cf48bc90740b4cd6090c82c9d) – AdamHurwitz Sep 25 '18 at 19:46
5

I suggested you the easiest way to implement Parcelable if you are using Android Studio.

Simply go to File->Settings->Plugins->Browse Repository and search for parcelable .See image

enter image description here It will automatically create Parcelable.

And there is a webiste also for doing this. http://www.parcelabler.com/

Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
3

You could pack your boolean values into a byte using masking and shifting. That would be the most efficient way to do it and is probably what they would expect you to do.

fleetway76
  • 1,600
  • 9
  • 12
  • +1. True, saving the value in a byte would be more efficient. Would you mind me editing my question to represent your idea? – Octavian Helm Jun 01 '11 at 12:54
  • You can, but what you have written isn't really what I meant. It will work but isnt the most efficient. You can pack 8 booleans into a byte using masks and boolean algebra – fleetway76 Jun 01 '11 at 13:11
  • On most cases I agree with you, however I do have cases that creep up from time to time where I need three states that Boolean works will with. Such as an optional yes/no question. I need the null to know whether the Boolean has explicitly been specified or not. – Chad Gorshing Nov 09 '11 at 04:23
  • There is no reason using byte over int, since the Parcel's `writeByte()` method directly calls `writeInt()` – Yaroslav Mytkalyk Jan 05 '16 at 10:27
3

It is hard to identify the real question here. I guess it is how to deal with booleans when implementing the Parcelable interface.

Some attributes of MyObject are boolean but Parcel don't have any method read/writeBoolean.

You will have to either store the value as a string or as a byte. If you go for a string then you'll have to use the static method of the String class called valueOf() to parse the boolean value. It isn't as effective as saving it in a byte tough.

String.valueOf(theBoolean);

If you go for a byte you'll have to implement a conversion logic yourself.

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

When unmarshalling the Parcel object you have to take care of the conversion to the original type.

Octavian Helm
  • 39,405
  • 19
  • 98
  • 102
  • There is absolutely no reason using String. There is no reason using byte over int, since the Parcel's `writeByte()` method directly calls `writeInt()`. The conversion logic is too verbose. Just do `writeInt(boolean ? 1 : 0)` and `boolean = readInt() != 0` – Yaroslav Mytkalyk Jan 05 '16 at 10:23
1

This question has already been answered perfectly by other people, if you want to do it on your own.

If you prefer to encapsulate or hide away most of the low-level parceling code, you might consider using some of the code I wrote some time ago for simplifying handling of parcelables.

Writing to a parcel is as easy as:

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

where color is an enum and isDriving is a boolean, for example.

Reading from a parcel is also not much harder:

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

Just take a look at the "ParceldroidExample" I added to the project.

Finally, it also keeps the CREATOR initializer short:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);
Michael Geier
  • 1,653
  • 1
  • 16
  • 18
1

There are many examples in the Android (AOSP) sources. For example, PackageInfo class has a boolean member requiredForAllUsers and it is serialized as follows:

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

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
FireAphis
  • 6,650
  • 8
  • 42
  • 63
0

For API 29 and above we can use

writeToParcel:

dest.writeBoolean(booleanFlag);

readFromParcel:

booleanFlag = in.readBoolean()

Or We can use

writeToParcel:

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

readFromParcel:

booleanFlag = in.readByte() != 0;

0

Since api 29, you can now use the readBoolean() in the Parcel class. see https://developer.android.com/reference/android/os/Parcel#readBoolean() for more

NightStorm
  • 101
  • 12