3

How do I break an object --- a Parcelable to be more specific; actually it's a bundle but the point is the same --- into a byte[]? I thought that the way I was doing it was a good solution but apparently I was mistaken.

Just for reference here is the old way I was doing it.

public static byte[] getBytes(Object obj) throws java.io.IOException {
    ByteArrayOutputStream bos   = new ByteArrayOutputStream();
    ObjectOutputStream oos      = new ObjectOutputStream(bos);
    oos.writeObject(obj);
    oos.flush();
    oos.close();
    bos.close();
    byte[] data = bos.toByteArray();
    return data;
}

Thanks ~Aedon

Edit 1::

Breaking an object like this passing a Bundle to it causes a NotSerializableException.

ahodder
  • 11,353
  • 14
  • 71
  • 114

3 Answers3

4

Your code looks mostly fine. I would suggest the following:

public static byte[] getBytes(Serializable obj) throws IOException {
    ByteArrayOutputStream bos   = new ByteArrayOutputStream();
    ObjectOutputStream oos      = new ObjectOutputStream(bos);
    oos.writeObject(obj);

    byte[] data = bos.toByteArray();

    oos.close();
    return data;
}
aroth
  • 54,026
  • 20
  • 135
  • 176
  • This is definitely the right way to do it. @Aedon - you may want to read up a little bit about serializing and unserializing objects to see if you will fall into any pitfalls (static attributes, etc) – Eric May 18 '11 at 23:56
  • Hah! Thanks, I never even noticed that I was closing before I was toByteArray. I'll see if that helps. Thanks. – ahodder May 19 '11 at 14:41
  • Nope, I'm getting a NotSerializableException. Prolly should have added that to the question, my bad. Updated. – ahodder May 19 '11 at 14:57
  • @AedonEtLIRA - The `NotSerializableException` means that the object your are trying to serialize does not implement the `Serializable` interface. This means that you cannot write it directly using an `ObjectOutputStream`. You will need to write your own code to serialize the object, either by copying whatever state you are interested in into something that is serializable like a `Map`, or by using other API's to convert your specific object type to bytes. – aroth May 19 '11 at 21:58
1

The question mentions Parcelable, which is not always Serializable. I think the right approach would be to write Parcelable to Parcel. Then use Parcel's marshall() method to write raw bytes out.

I played a little with it. If your Parcelable follows the protocol, following code writes out correct byte array for Parcelable. Assume that MyParcelable contains 2 strings and one int.

            Parcel parcel1 = Parcel.obtain();
            MyParcelable parcelable1 = new MyParcelable("a", "b", 25);
            parcelable1.writeToParcel(parcel1, 0);

            byte content[] = parcel1.marshall();
            parcel1.recycle();
            Parcel parcel2 = Parcel.obtain();
            parcel2.unmarshall(content, 0, content.length);
            parcel2.setDataPosition(0);
            MyParcelable parcelable2 = MyParcelable.CREATOR.createFromParcel(parcel2);
            parcel2.recycle();
            Toast.makeText(context, parcelable2.a + " " + parcelable2.b + " " + parcelable2.val, Toast.LENGTH_LONG).show();

Also see How to use Parcel in Android?

Community
  • 1
  • 1
Alex Gitelman
  • 24,429
  • 7
  • 52
  • 49
  • @Alex Gitelman could you provide a link to the documentation you are talking about I would like to read further. Whats the harm in writing it to disc more specifically. – Nathan Schwermann May 19 '11 at 02:30
  • @schwiz http://developer.android.com/reference/android/os/Parcel.html#marshall%28%29 suggests that this mechanism is intended for IPC and is not guaranteed to be compatible across platforms. I think it should be ok for short term storage locally but not for network communications,for example. Anyway, I removed my FileOutputStream code to prevent confusion. – Alex Gitelman May 19 '11 at 03:07
  • @Alex Gitelman, I just read the doc on marshall. It says that I should not use the buye data on persistant storage. Any idea why? I need the data to be stored in a database. – ahodder May 19 '11 at 15:07
  • 1
    @AedonEtLIRA I think what docs say is that APIs make no attempt to have data compatible across different versions of Android. That means that if you store it long term in the database and then user upgrades their device, it is not guaranteed to unmarshall correctly. Same deal if you want to send it across network to different device. So you need to identify your specific use case. If you only need it for short term storage like caching or similar it is probably OK. In other words, if you need to read it on the same device on the same day - it's probably fine. – Alex Gitelman May 19 '11 at 16:26
  • @Alex, Ah. Hmmm. That is not what I need then. Thanks though. – ahodder May 19 '11 at 17:21
  • You will probably need to make it serializable, then and follow regular serialization as in your original sample and other answer. Good Luck! – Alex Gitelman May 19 '11 at 18:01
0

Use Okio library that is a convenient replacement for ByteArrayOutputStream and with more powerful API.

public static byte[] getBytes(Serializable obj) throws IOException {
    Buffer buffer = new Buffer();
    ObjectOutputStream objectOut = new ObjectOutputStream(buffer.outputStream());
    objectOut.writeObject(obj);
    objectOut.close();
    return buffer.readByteArray();
}