I created a class, which has several member variables, all of which are serializable... except one Bitmap! I tried to extend bitmap and implement serializable, not thinking Bitmap is a final class.
I want to save the class (it basically forms the current state of a game) so a player can pick-up and load the game.
The way I see it I have two options: 1) Find another way to save the game state. Any help here would be appreciated.
2) change the bitmap member variable to an int, say, and create a BitmapGetter class that has a static method returning bitmaps based on ints. (This option is not easy, as my class contains so many bitmap possiblities and the way I created the game means this will require an incredible amount of effort.
Basically I have no one to blame but myself for lazily creating a bitmap variable without thinking, but I would appreciate any help...
How about replacing Bitmap with a class like this:
public class SerialBitmap implements Serializable {
    public Bitmap bitmap;
    // TODO: Finish this constructor
    SerialBitmap(<some params>) {
        // Take your existing call to BitmapFactory and put it here
        bitmap = BitmapFactory.decodeSomething(<some params>);
    }
    // Converts the Bitmap into a byte array for serialization
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteStream);
        byte bitmapBytes[] = byteStream.toByteArray();
        out.write(bitmapBytes, 0, bitmapBytes.length);
    }
    // Deserializes a byte array representing the Bitmap and decodes it
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        int b;
        while((b = in.read()) != -1)
            byteStream.write(b);
        byte bitmapBytes[] = byteStream.toByteArray();
        bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
    }
}
The overridden Serializable.writeObject() and readObject() methods serialize the bytes instead of the Bitmap so the class is serializable. You will need to finish the constructor because I don't know how you currently construct your Bitmap. The last thing to do is to replace references to YourClass.bitmap with YourClass.serialBitmap.bitmap.
Good luck!
Barry P.S. This code compiles but I haven't tested it with a real bitmap
I had the same problem.
And i decided like this.
Bitmap is Parcelable, so I made following to my class.
I made Constructor which gets Bundle object , and getter that
returns Bundle representing Objects data. So while Bitmap is
parcelable , Bundle can save bitmap as parcelable in it.  
When you need to pass Date in intent , you can call objects
getBundle() method  and pass with Intent.putExtra(String key,Bundle value)
In target activity you will call getBundle(String key) and pass it
to constructor.
I think it's very easy approach.
Here is a general bitmap wrapper: (Edit from Barry Fruitman answer)
    public class SerialBitmap implements Serializable {
    private Bitmap bitmap;
    private transient Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.PNG;
    private transient int compressQuality = 100;
    public SerialBitmap(Bitmap bitmap)
    {
        this.bitmap = bitmap;
    }
    public Bitmap getBitmap() {
        return bitmap;
    }
    public void recycle() {
        if (bitmap!=null && !bitmap.isRecycled()) bitmap.recycle();
    }
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(compressFormat, compressQuality, stream);
        byte[] byteArray = stream.toByteArray();
        out.writeInt(byteArray.length);
        out.write(byteArray);
    }
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        int bufferLength = in.readInt();
        byte[] byteArray = new byte[bufferLength];
        int pos = 0;
        do {
            int read = in.read(byteArray, pos, bufferLength - pos);
            if (read != -1) {
                pos += read;
            } else {
                break;
            }
        } while (pos < bufferLength);
        bitmap = BitmapFactory.decodeByteArray(byteArray, 0, bufferLength);
    }
    public Bitmap.CompressFormat getCompressFormat() {
        return compressFormat;
    }
    public void setCompressFormat(Bitmap.CompressFormat compressFormat) {
        this.compressFormat = compressFormat;
    }
    public int getCompressQuality() {
        return compressQuality;
    }
    public void setCompressQuality(int compressQuality) {
        this.compressQuality = compressQuality;
    }
}
if you want to compress the bitmap and make the serial object smaller
you can set the compression via setCompressFormat and setCompressQuality.
Example:
setCompressFormat(Bitmap.CompressFormat.JPEG);
setCompressQuality(80);
If you are using Progourd, add the following rules:
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
                        If it is OK to save the bitmap data separately in your application, you can do the following:
In your class that saves the current state, save the bitmap to a folder of your choice:
FileOutputStream out = new FileOutputStream(<path to bmp>);
bitmap.compress(CompressFormat.PNG, 100, out);
In the class that has the bitmap as member, have the path as the serializable member and reconstruct the bitmap after deserialization:
public class MyClass implements Serializable
{
    // ...
    private String bitmapPath;
    transient Bitmap bitmap;
    // ...
    private void writeObject(ObjectOutputStream out) throws IOException
    {
        out.defaultWriteObject();
    }
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        bitmap = BitmapFactory.decodeFile(path);
    }
You can implement any other build-up functionality in the readObject() function if needed, since the object is fully constructed after the defaultReadObject() call.
Hope this helps.
BTW, http://developer.android.com/reference/android/os/Parcel.html recommends against using Parcelable for serialization purposes. I do not have enough points yet to leave a comment, so I am editing my own answer to put in this remark.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With