0

I have an Android app that one can use to store useful information on all the wines one tastes (name, year, price, how good it is...). So as to allow users to exchange information between one another or accros their different devices, I have a Serialization mechanism that allows user to:

  • export all the Wines into a .ser file
  • choose Wines to import from any such file

This works fine.

However, some time ago, I got a request to also export the pictures that one can add to a Wine description. So I modified my Wine class (which implements Serializable) to add a byte[] attribute.

And this is where trouble begins: when exporting my Wines with pictures, I get a StreamCorruptedException.

java.io.StreamCorruptedException
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1528)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
at [...].WineVectorSerializer$2.run(WineVectorSerializer.java:84)

I toyed a little with the way I created the byte array from the Bitmap and kept reducing size, until it finally worked. I don't know why, but the Exception is triggered when my .ser file reaches ~1.3Mo.

So if I export all the pictures in crappy quality, everything works. If I increases it just a little bit, then I get the exception when the export file becomes 'too big' (less than 2 Mo isn't that much - and I got plenty of free space on my SD card).

I tried to add a Thread.sleep(1000) between each call to writeObject, but it didn't help.



Code samples

Serialize into a file

FileOutputStream fos = new FileOutputStream(filename);
final ObjectOutputStream out = new ObjectOutputStream(fos);

for (Wine aWine: data) {

  try {
    aWine.loadImage();
    out.writeObject(aWine);
    out.flush();
  } 
  catch (IOException e) {
    Log.e("Serialize", "Error during export");
    exportError = true;
    handle.sendMessage(handle.obtainMessage());
    break;
  }
  finally {
    aWine.freeImage();
  }
  handle.sendMessage(handle.obtainMessage());
}
out.close();

In the above snippet, you can see that I call loadImage() [see next snippet] and freeImage(). The first one:

  • loads the image from the disc if it exists (check on an imagePath attribute in Wine) into a Bitmap object
  • converts it into a byte[] to be store in one of Wine's attribute to be serialized

After a Wine has been serialized, the call to freeImage() sets this byte[] to null to as to allow the garbage collector to free some memory and avoid out of memory exception - which would be bound to happen when exporting 300+ Wines with pictures.

Load the image

public void loadImage() {
  set_imageBytes(null);
  if (_imagePath != null && _imagePath.length() > 0) {

      File aImageFile = new File(_imagePath);

      // Just to get the image size
      BitmapFactory.Options options = new BitmapFactory.Options();
      options.inJustDecodeBounds = true;
      BitmapFactory.decodeFile(aImageFile.getAbsolutePath(), options);

      // No more than 500px
      int largestEdge = Math.max(options.outHeight, options.outWidth);
      int ratio = largestEdge/500;

      options.inJustDecodeBounds = false;
      options.inSampleSize = ratio;
      Bitmap aBitmap = BitmapFactory.decodeFile(aImageFile.getAbsolutePath(), options);
      if (aBitmap != null) {
          Log.i("Serialize", "There is an image to serialize");
          ByteArrayOutputStream stream = new ByteArrayOutputStream();
          aBitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream);
          set_imageBytes(stream.toByteArray());
      }
  }
}

In the above code, I manage to avoid the exception by setting the max width to 200px and the quality to 5% in aBitmap.compress.

If anyone could explain why this exception happens around the 1.3 Mo barrier, that would be awesome. Thanks in advance :)

Anordil
  • 160
  • 8
  • 1
    Please show the complete exception – Jon Skeet Jan 28 '15 at 15:40
  • I edited my question to add the stacktrace – Anordil Jan 28 '15 at 15:46
  • It is always useful to `flush()` and `close()` all and any streams before you attempt to use the data, and I think that earlier similar question http://stackoverflow.com/questions/5771434/objectoutputstream-and-java-io-streamcorruptedexception implies the same – Germann Arlington Jan 28 '15 at 17:02
  • The file isn't read while it's being written. This is not a sender-receiver context, as I'm writting the file to the SD card. As you can see in the snippet of code, I do flush the stream after writing each object. I cannot close it before having written all the objects, though. Plus, as I said, the exception solely occurs when the size of the output file exceeds 1.3 Mo. – Anordil Jan 29 '15 at 07:04
  • Is that the *entire* stack trace? Isn't there a 'caused by' further down? – user207421 Jan 29 '15 at 11:59

1 Answers1

0

Got it to work. I was just stupid enough to misread the available space on my SD card, the exception is thrown when there is no space left to write on.

user207421
  • 305,947
  • 44
  • 307
  • 483
Anordil
  • 160
  • 8