Сериализуемая проблема Android - PullRequest
10 голосов
/ 14 мая 2011

Я создал класс, который имеет несколько переменных-членов, все из которых являются сериализуемыми ... кроме одного растрового изображения! Я пытался расширить растровое изображение и реализовать сериализуемый, не думая, что растровое изображение является окончательным классом.

Я хочу сохранить класс (он в основном формирует текущее состояние игры), чтобы игрок мог забрать и загрузить игру.

То, как я это вижу, у меня есть два варианта: 1) Найти другой способ сохранить состояние игры. Любая помощь здесь будет оценена.

2) измените переменную-член bitmap, скажем, на int, и создайте класс BitmapGetter, у которого есть статический метод, возвращающий растровые изображения на основе целых чисел. (Этот вариант не прост, так как мой класс содержит так много возможностей для растровых изображений, а способ, которым я создал игру, означает, что это потребует невероятных усилий.

В принципе, мне некого винить, кроме себя за то, что лениво создавал переменную растрового изображения без размышлений, но я был бы признателен за любую помощь ...

Ответы [ 6 ]

14 голосов
/ 14 мая 2011

Как насчет замены 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 () сериализуют байты вместо битовой карты, чтобы класс был сериализуемым Вам нужно будет закончить конструктор, потому что я не знаю, как вы в настоящее время создаете свое растровое изображение. Последнее, что нужно сделать, это заменить ссылки на YourClass.bitmap на YourClass.serialBitmap.bitmap.

Удачи!

Barry Постскриптум Этот код компилируется, но я не проверял его с настоящим растровым изображением

2 голосов
/ 26 февраля 2015

У меня была такая же проблема.

И я решил вот так.

Bitmap равно Parcelable, поэтому я сделал следующее для своего класса.

  1. Я сделал Конструктор , которыйполучает Bundle объект и getter , который возвращает Bundle , представляющий данные объектов.Таким образом, в то время как Растровое изображение является подлежащим обработке , Связка может сохранить растровое изображение как обрабатываемое .

  2. Когда вам нужно передать Дата намеренно, вы можете вызывать объекты getBundle() метод и передавать с Intent.putExtra(String key,Bundle value)

  3. В целевой деятельностиВы позвоните getBundle(String key) и передадите его конструктору .

    Я думаю, что это очень простой подход.

1 голос
/ 04 октября 2018

Вот общая растровая оболочка: (Правка от Барри Фрутман)

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

, если вы хотите сжать растровое изображение и уменьшить размер последовательного объекта Вы можете установить компрессию с помощью setCompressFormat и setCompressQuality.

Пример:

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();
}
0 голосов
/ 10 июля 2011

Если все в порядке, чтобы сохранить данные растрового изображения отдельно в вашем приложении, вы можете сделать следующее:

В вашем классе, который сохраняет текущее состояние, сохраните растровое изображение в папку по вашему выбору:

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().

Надеюсь, это поможет.

Кстати, http://developer.android.com/reference/android/os/Parcel.html рекомендует не использовать Parcelable для целей сериализации. У меня еще недостаточно очков, чтобы оставить комментарий, поэтому я редактирую свой собственный ответ, чтобы добавить это замечание.

0 голосов
/ 14 мая 2011

Вы можете выполнить сериализацию вручную, используя следующие методы 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

0 голосов
/ 14 мая 2011

Прежде всего, вы должны сериализовать через Parcelable .Это класс Android, и он обычно отлично работает, из коробки: с ним можно сериализовать ByteArray, используя методы:

public final void writeByteArray (byte[] b)

и

public final void readByteArray (byte[] val)

Возможно, вы захотитепроверить посылку документацию тоже.

...