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


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

9 95

9 ответов:

От "Pro 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 это не сериализуемый.


enter image description here

с ПОЧЕМУ МЫ ЛЮБИМ PARCELABLE


enter image description here

с Parcelable vs Serializable

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

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

в данной статье проясните вещи, а также:

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

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

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

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

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

Так это до вас, чтобы решить, если оно того стоит.

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

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

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

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

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

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

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

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