Преимущество использования Parcelable вместо сериализации объекта

Насколько я понимаю, Bundle а также Parcelable принадлежит тому, как Android выполняет сериализацию. Он используется, например, при передаче данных между действиями. Но мне интересно, есть ли какие-либо преимущества в использовании Parcelable вместо классической сериализации в случае сохранения состояния моих бизнес-объектов, например, во внутреннюю память? Будет ли это проще или быстрее классического способа? Где я должен использовать классическую сериализацию и где лучше использовать связки?

9 ответов

Решение

Из "Про Android 2"

ПРИМЕЧАНИЕ. Видение Parcelable могло вызвать вопрос: почему Android не использует встроенный механизм сериализации Java? Оказывается, команда Android пришла к выводу, что сериализация в Java слишком медленная, чтобы удовлетворить требования Android к межпроцессному взаимодействию. Поэтому команда создала решение Parcelable. Подход Parcelable требует явной сериализации членов вашего класса, но в конце вы получаете намного более быструю сериализацию ваших объектов.

Также следует понимать, что Android предоставляет два механизма, которые позволяют передавать данные другому процессу. Первый - передать пакет в действие с помощью намерения, а второй - передать Parcelable в службу. Эти два механизма не являются взаимозаменяемыми и их не следует путать. То есть Parcelable не предназначен для передачи в действие. Если вы хотите начать действие и передать ему некоторые данные, используйте пакет. Parcelable предназначен для использования только как часть определения AIDL.

Serializable комично медленно на Android. Граница бесполезна во многих случаях на самом деле.

Parcel а также Parcelable фантастически быстрые, но в документации говорится, что вы не должны использовать их для сериализации общего назначения в хранилище, поскольку реализация зависит от версии Android (например, обновление ОС может привести к поломке приложения, на которое она опирается).

Наилучшее решение проблемы сериализации данных в хранилище с разумной скоростью - это сделать это самостоятельно. Я лично использую один из моих собственных служебных классов, который имеет аналогичный интерфейс Parcel и который может очень эффективно сериализовать все стандартные типы (за счет безопасности типов). Вот сокращенная версия этого:

public interface Packageable {
    public void readFromPackage(PackageInputStream in)  throws IOException ;
    public void writeToPackage(PackageOutputStream out)  throws IOException ; 
}


public final class PackageInputStream {

    private DataInputStream input;

    public PackageInputStream(InputStream in) {
        input = new DataInputStream(new BufferedInputStream(in));
    }

    public void close() throws IOException {
        if (input != null) {
            input.close();
            input = null;
        }       
    }

    // Primitives
    public final int readInt() throws IOException {
        return input.readInt();
    }
    public final long readLong() throws IOException {
        return input.readLong();
    }
    public final long[] readLongArray() throws IOException {
        int c = input.readInt();
        if (c == -1) {
            return null;
        }
        long[] a = new long[c];
        for (int i=0 ; i<c ; i++) {
            a[i] = input.readLong();
        }
        return a;
    }

...

    public final String readString()  throws IOException {
        return input.readUTF();
    }
    public final <T extends Packageable> ArrayList<T> readPackageableList(Class<T> clazz) throws IOException {
        int N = readInt();
        if (N == -1) {
            return null;
        }
        ArrayList<T> list = new ArrayList<T>();
        while (N>0) {
            try {
                T item = (T) clazz.newInstance();
                item.readFromPackage(this);
                list.add(item);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            N--;
        }
        return list;
    }

}



public final class PackageOutputStream {

    private DataOutputStream output;

    public PackageOutputStream(OutputStream out) {
        output = new DataOutputStream(new BufferedOutputStream(out));
    }

    public void close() throws IOException {
        if (output != null) {
            output.close();
            output = null;
        }
    }

    // Primitives
    public final void writeInt(int val) throws IOException {
        output.writeInt(val);
    }
    public final void writeLong(long val) throws IOException {
        output.writeLong(val);
    }
    public final void writeLongArray(long[] val) throws IOException {
        if (val == null) {
            writeInt(-1);
            return;
        }
        writeInt(val.length);
        for (int i=0 ; i<val.length ; i++) {
            output.writeLong(val[i]);
        }
    }

    public final void writeFloat(float val) throws IOException {
        output.writeFloat(val);
    }
    public final void writeDouble(double val) throws IOException {
        output.writeDouble(val);
    }
    public final void writeString(String val) throws IOException {
        if (val == null) {
            output.writeUTF("");
            return;
        }
        output.writeUTF(val);
    }

    public final <T extends Packageable> void writePackageableList(ArrayList<T> val) throws IOException {
        if (val == null) {
            writeInt(-1);
            return;
        }
        int N = val.size();
        int i=0;
        writeInt(N);
        while (i < N) {
            Packageable item = val.get(i);
            item.writeToPackage(this);
            i++;
        }
    }

}

Посмотрите, как быстро Parcelable, чем Serializable.


введите описание изображения здесь

ПОЧЕМУ МЫ ЛЮБИМ ЧТОБЫ


введите описание изображения здесь

от Parcelable vs Serializable

Если вам нужна сериализация, например, для целей хранения, но вы хотите избежать потери скорости отражения, вызванной интерфейсом Serializable, вы должны явно создать свой собственный протокол сериализации с интерфейсом Externalizable.

При правильной реализации это соответствует скорости Parcelable, а также учитывает совместимость между различными версиями Android и / или платформы Java.

Эта статья также может прояснить ситуацию:

В чем разница между Serializable и Externalizable в Java?

С другой стороны, это также самая быстрая техника сериализации во многих тестах, превосходящая Kryo, Avro, Protocol Buffers и Jackson (json):

http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

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

Согласно тестам, показанным на этом сайте, Parcelable примерно в 10 раз быстрее на новейших устройствах (например, nexus 10) и примерно на 17 быстрее на старых (например, desire Z).

так что вам решать, стоит ли это того.

может быть, для относительно небольших и простых классов Serializable - это хорошо, а для остальных вы должны использовать Parcelable

Parcelable в основном связан с IPC, использующим инфраструктуру Binder, где данные передаются как Parcels.

Поскольку Android во многом, если не во всех задачах IPC, во многом зависит от Binder, имеет смысл реализовать Parcelable в большинстве мест, особенно в среде, потому что он позволяет передавать объект другому процессу, если вам это нужно. Это делает объекты "транспортабельными".

Но если у вас есть бизнес-уровень, не относящийся к Android, который широко использует сериализуемые для сохранения состояний объектов, и вам нужно только сохранить их в файловой системе, то я думаю, что сериализуемый - это хорошо. Это позволяет избежать кода Parcelable.

Я просто использую GSON -> Serialise to JSON String -> Восстановить объект из JSON String.

На основании этой статьи http://www.mooproductions.org/node/6?page=5 Parcelable должен быть быстрее.

В статье не упоминается, что я не думаю, что сериализуемые объекты будут работать в AIDL для удаленных сервисов.

Кроме того, Parcelable предлагает пользовательскую реализацию, в которой пользователь получает возможность разбирать каждый из своих объектов, переопределяя writeToParcel(). Однако сериализация не делает эту пользовательскую реализацию, поскольку ее способ передачи данных включает API отражения JAVA.

Другие вопросы по тегам