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