Android可序列化问题

时间:2011-05-14 15:29:17

标签: android bitmap serializable

我创建了一个类,它有几个成员变量,所有这些都是可序列化的......除了一个Bitmap!我试图扩展位图并实现可序列化,而不是认为Bitmap是最后一类。

我想保存课程(它基本上形成了游戏的当前状态),因此玩家可以提升并加载游戏。

我看到它的方式我有两个选择: 1)找到另一种保存游戏状态的方法。这里的任何帮助将不胜感激。

2)将位图成员变量更改为int,比如说,并创建一个BitmapGetter类,该类具有基于int返回位图的静态方法。 (这个选项并不容易,因为我的类包含了很多位图可能性,而且我创建游戏的方式意味着需要花费大量精力。

基本上我没有人责怪,但我自己懒得创建一个位图变量而不考虑,但我会感激任何帮助......

6 个答案:

答案 0 :(得分:14)

如何用这样的类替换Bitmap:

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

重写的Serializable.writeObject()和readObject()方法序列化字节而不是Bitmap,因此该类是可序列化的。您将需要完成构造函数,因为我不知道您当前如何构造您的Bitmap。最后要做的是用YourClass.serialBitmap.bitmap替换对YourClass.bitmap的引用。

祝你好运!

巴里 附:这段代码编译但我还没有用真正的位图测试它

答案 1 :(得分:2)

我遇到了同样的问题。

我决定这样。

BitmapParcelable,所以我跟随我的班级。

  1. 我创建了构造函数,它获取了Bundle个对象, getter 返回表示对象数据的 Bundle 。所以,虽然 Bitmap parcelable Bundle 可以将位图保存为 parcelable

  2. 当您需要在意图中传递日期时,您可以调用对象 getBundle()方法并通过Intent.putExtra(String key,Bundle value)

  3. 传递
  4. 在目标活动中,您将调用getBundle(String key)并将其传递 到构造函数

    我认为这很简单。

答案 2 :(得分:1)

这是一个通用的位图包装器:(根据Barry Fruitman的答案编辑)

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

如果要压缩位图并使串行对象更小 您可以通过setCompressFormatsetCompressQuality设置压缩率。

示例:

setCompressFormat(Bitmap.CompressFormat.JPEG);
setCompressQuality(80);

如果您使用的是Progourd,请添加以下规则:

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

答案 3 :(得分:0)

首先,您应该通过Parcelable序列化。它是一个Android类,它通常很好用,开箱即用:你可以使用方法序列化ByteArray:

public final void writeByteArray (byte[] b)

public final void readByteArray (byte[] val)

您可能也想查看Parcel文档。

答案 4 :(得分:0)

您可以使用以下java方法手动执行序列化:

private void writeObject(java.io.ObjectOutputStream out)
private void readObject(java.io.ObjectInputStream in)

使用getPixels序列化位图,当您进行反序列化时,可以使用createBitmap从头开始重新创建它。

您可以在此处阅读有关如何使用readObject和writeObject的信息:http://download.oracle.com/javase/6/docs/api/java/io/Serializable.html

答案 5 :(得分:0)

如果可以在应用程序中单独保存位图数据,则可以执行以下操作:

在保存当前状态的类中,将位图保存到您选择的文件夹中:

FileOutputStream out = new FileOutputStream(<path to bmp>);
bitmap.compress(CompressFormat.PNG, 100, out);

在具有位图作为成员的类中,将路径作为可序列化成员并在反序列化后重构位图:

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

如果需要,您可以在readObject()函数中实现任何其他构建功能,因为该对象是在defaultReadObject()调用后完全构造的。

希望这有帮助。

BTW,http://developer.android.com/reference/android/os/Parcel.html建议不要使用Parcelable进行序列化。我还没有足够的意见留下评论,所以我正在编辑我自己的答案以加入这句话。