- Parcelable. Передаём объекты
- Полный список
- Русские Блоги
- Android два метода сериализации Serializable и Parcelable
- Что такое сериализация
- Сериализуемый интерфейс
- serialVersionUID
- Сериализация и десериализация Serializable
- Parcelable интерфейс
- подводить итоги
- 1. Что такое сериализация и десериализация?
- (1) Объяснение терминов
- (2) Подробное объяснение сериализации
- Во-вторых, чем отличается Java-объект от сериализации Java-объекта?
- 3. Зачем использовать сериализацию и десериализацию?
- 4. В чем разница между Serializable и Parcelable в Android?
- Пять, пример Parcelable
- Шесть, принцип посылки
- Семь, сериализация и десериализация Parcelable эксперимент?
Parcelable. Передаём объекты
Очень часто программисту приходится передавать данные из одной активности в другую. Когда речь идёт о простых типах, то используется метод intent.putExtra() и ему подобные. Данный способ годится для типов String, int, long или массивов. А вот объекты таким образом передать не получится.
В Java существует специальный интерфейс Serializable, но он оказался слишком неповоротлив для мобильных устройств и пользоваться им настоятельно не рекомендуется. Для передачи объектов следует использовать другой интерфейс Parcelable.
В интерфейсе Parcelable используются два метода describeContents() и writeToParcel():
Метод describeContents() описывает различного рода специальные объекты, описывающие интерфейс.
Метод writeToParcel() упаковывает объект для передачи.
Также необходимо реализовать статическое поле Parcelable.Creator CREATOR, которое генерирует объект класса-передатчика.
Напишем пример. Попробуем передать объект «Мои документы». Как известно, признаком настоящего документа являются Усы, лапы, хвост (я ещё добавил бы имя). Создадим новый класс DocumentInfo, который реализует интерфейс Parcelable:
Теперь мы может передать объект через Intent. Создадим две активности. В первой активности напишем код для отправки объекта:
Вторая активность должна принять данные от первой активности:
Получив объект из первой активности, мы можем извлечь необходимые данные и разложить по полочкам.
Если класс слишком большой, то вручную его переделывать утомительно. Существует онлайн-сервис parcelabler а также плагин для Android Studio mcharmas/android-parcelable-intellij-plugin: IntelliJ Plugin for Android Parcelable boilerplate code generation.
Источник
Полный список
— знакомимся с Parcel
Сам по себе Parcel мне никогда еще использовать не приходилось и не знаю, придется ли. Меня он заинтересовал, когда я начал разбираться с интерфейсом Parcelable. Этот интерфейс используется при передаче объектов через Intent и мне стало интересно, как создавать свои объекты с поддержкой такой передачи. В итоге я немного разобрался в Parcel и Parcelable, хотя понял далеко не все. Попробую теперь рассказать об этом.
Parcel – это контейнер для передачи данных. У него есть куча методов для помещения и извлечения данных. В этом уроке рассмотрим самые простейшие из них.
Project name: P0681_Parcel
Build Target: Android 2.3.3
Application name: Parcel
Package name: ru.startandroid.develop.p0681parcel
Create Activity: MainActivity
В этом уроке экран нам не понадобится, main.xml оставляем без изменений. Работать будем с логом.
Кодим в MainActivity.java:
Метод writeParcel – получаем экземпляр Parcel, описываем набор переменных и пишем их в Parcel, используя для этого соответствующие методы. После каждой записи выводим в лог информацию о Parcel, используя метод logWriteInfo.
Метод logWriteInfo пишет в лог данные о Parcel. dataSize – это объем записанных данных.
Методы readParcel и logReadInfo – пока пустые. Позже заполним.
Все сохраняем и запускаем приложение. Смотрим лог.
before writing: dataSize = 0
byte: dataSize = 4
int: dataSize = 8
long: dataSize = 16
float: dataSize = 20
double: dataSize = 28
String: dataSize = 52
Разбираем по порядку.
before writing: перед записью у нас размер данных равен 0. Записали byte: dataSize = 4 (для записи данных типа byte использовались 4 байта). Записали int: dataSize = 8 (для записи данных типа int использовались еще 4 байта в дополнение к ранее заполненным 4 байтам для byte). Записали long: dataSize = 16 (для записи long использовались еще 8 байтов в дополнение к ранее заполненным 8 байтам для byte и int). И т.д. В итоге видим, что dataSize показывает, сколько всего занято байт.
Обратите внимание, что типы int, long, float и double заняли столько байт, сколько они действительно занимают в Java – соответственно 4, 8, 4 и 8. byte – вместо одного байта почему-то занял целых 4. А String под каждый символ использует два байта, но пишет еще служебную информацию, поэтому получается больше.
Теперь попробуем прочесть то, что записали. Заполним пустые методы чтения:
В методе readParcel мы устанавливаем (метод setDataPosition) позицию в 0, т.к. нам нужно читать с начала. Читаем данные в том же порядке, как и записывали: byte, int, long, float, double, String. В лог выводим результат чтения и текущую позицию (dataPosition).
Все сохраним, запустим приложение и смотрим лог.
Первые строки лога про запись нам уже знакомы. Нас интересуют строки чтения.
before reading: dataPosition = 52
byte = 1: dataPosition = 4
int = 2: dataPosition = 8
long = 3: dataPosition = 16
float = 4.0: dataPosition = 20
double = 5.0: dataPosition = 28
string = abcdefgh: dataPosition = 52
Перед тем, как мы установим позицию в 0 (before reading), видим, что она равна 52. Там она находится после записи. Каждая запись данных перемещает позицию на кол-во, равное размеру записываемых данных. Размер всех последовательно записанных данных у нас составил 52, и позиция соответственно переместилась в 52. Вы можете в качестве эксперимента выводить в лог позицию после каждой записи данных. Я же вывожу только для процедур чтения.
Итак, мы устанавливаем позицию в 0 и начинаем читать данные. Прочли значение byte, оно равно 1, как мы и записывали. Позиция сместилась на размер прочтенного значения, и теперь мы будем читать с позиции 4. Читаем int, оно равно 2, позиция сместилась и равна 8. И т.д.
Все значения, которые мы последовательно записывали, мы в том же порядке считали. Здесь надо понимать, что если вы записали int, а читать потом будете double, то результат получится не тот, что нужен. Т.к. int пишет 4 байта, а double считывает 8. Тем самым он залезет на следующий записанный тип и возьмет из него недостающие 4 байта. Получится каша. Поэтому тут надо быть аккуратным.
Вы всегда можете установить нужную вам позицию и считать хранимое значение. Главное – знать, какой тип там хранится. Например, у нас сейчас при записи double пишется с позиции 20. Поэтому мы можем перевести позицию в 20 и выполнить readDouble. Мы успешно получим записанный туда double, а позиция станет равна 28.
Если вы хотите глянуть содержимое Parcel можно использовать его метод marshall(), он вернет массив записанных в Parcel байтов.
Вот такой краткий экскурс. Эти знания понадобятся для понимания следующего урока.
На следующем уроке:
— добавляем своему объекту поддержку Parcelable
— передаем объект с помощью Intent
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Русские Блоги
Android два метода сериализации Serializable и Parcelable
Что такое сериализация
Мы всегда говорим или слышим о «сериализации». Каково ее определение?
Сериализация (сериализация) Процесс преобразования информации о состоянии объекта в форму, которая может быть сохранена или передана. Во время сериализации объект записывает свое текущее состояние во временное или постоянное хранилище. Позже вы можете воссоздать объект, прочитав или десериализуя состояние объекта из области хранения.
Двоичная сериализация поддерживает точность типов, что полезно для сохранения состояния объектов между различными вызовами приложения. Например, сериализуя объект в буфер обмена, вы можете использовать его в разных приложениях. Вы можете сериализовать объекты в потоки, диски, память, сети и т. Д. Удаленное взаимодействие использует сериализацию для передачи объектов между компьютерами или доменами приложений «по значению».
Проще говоря, «сериализация» — это преобразование состояния объекта во время выполнения в двоичное, а затем сохранение его в потоке, в памяти или передача на другие терминалы по сети.
В разработке под Android мы часто используем Intent при передаче данных в компонентах. При передаче данных нам необходимо передать Serializable или Parcelable данные, такие как метод Intent.putExtra:
Binder также будет использоваться для передачи данных.
Сегодня я представлю эти два метода сериализации.
Сериализуемый интерфейс
Serializable — это интерфейс сериализации, предоставляемый Java, это пустой интерфейс:
Serializable используется для идентификации текущего класса, может быть ObjectOutputStream Сериализация и бытие ObjectInputStream Десериализация.
Serializable имеет следующие характеристики:
- В сериализуемом классе состояние атрибута, которое не реализует Serializable, не может быть сериализовано / десериализовано
- Другими словами, в процессе десериализации класса его несериализуемые свойства будут воссозданы путем вызова конструктора без параметров.
- Следовательно, конструктор без параметров этого свойства должен быть доступен, иначе во время выполнения будет сообщено об ошибке.
- Класс, реализующий сериализацию, и его подклассы также сериализуемы.
Ниже приведен класс сущности, реализующий Serializable:
Видно, что реализация Serializable очень проста, за исключением содержимого сущности, просто создайте его serialVersionUID Атрибуты в порядке.
serialVersionUID
По названию видно, что это serialVersionUID Что-то похожее на наш обычный номер версии интерфейса, который однозначно определяет сериализуемый класс во время выполнения.
Другими словами, когда класс сериализуется, его номер версии будет сохранен во время выполнения, а затем во время десериализации проверьте, совпадает ли номер версии объекта, который вы хотите десериализовать. Если он не согласован, будет сообщено об ошибке: · InvalidClassException 。
Если мы не создадим этот номер версии сами, среда выполнения вычислит номер версии по умолчанию на основе многих характеристик класса в процессе сериализации. Однако, если вы немного измените этот класс, номер версии изменится. Если это произойдет после сериализации, это вызовет вышеупомянутую ошибку во время десериализации.
Поэтому спецификация JVM настоятельно рекомендует объявлять номер версии вручную. Это число может быть случайным, если оно фиксировано. В то же время лучше оставаться конфиденциальным и окончательным и постараться сохранить его неизменным.
Кроме того, статические и временные измененные атрибуты не сохраняются в процессе сериализации. Первый хорошо понятен, потому что статические атрибуты управляются классом и не принадлежат состоянию объекта; в то время как последний является ключевым словом Java, специально используемым для идентификации непоследовательности. Атрибуты.
Реализация Serializable по умолчанию не будет создана автоматически. serialVersionUID Атрибут, чтобы напоминать нам создавать вовремя serialVersionUID , Можно поискать в настройках serializable Затем выберите несколько вариантов, как показано на рисунке ниже, для тех, кто не заявил serialVersionUID Добавьте предупреждение для классов атрибутов и внутренних классов.
Поэтому, когда мы создаем класс без объявления атрибута UID, на имени класса будет желтое предупреждение:
Содержимое предупреждения будет отображаться при наведении на него мыши:
GroupBean’ does not define a ‘serialVersionUID’ field less… (Ctrl+F1)
Reports any Serializable classes which do not provide a serialVersionUID field. Without a serialVersionUID field, any change to a class will make previously serialized versions unreadable.
В это время мы можем сгенерировать serialVersionUID, нажав комбинацию клавиш для запроса кода.
Сериализация и десериализация Serializable
Сериализация и десериализация Serializable выполняются через ObjectOutputStream и ObjectInputStream соответственно. Пример кода выглядит следующим образом:
Parcelable интерфейс
Parcelable — это интерфейс сериализации, уникальный для Android:
Классы, реализующие интерфейс Parcelable, будут преобразованы в при сериализации и десериализации. Parcel Тип данных.
Parcel является носителем, он может содержать ссылки на данные или объекты, а затем передаваться между процессами через IBinder.
Класс, реализующий интерфейс Parcelable, должен иметь статическую переменную типа CREATOR. Ниже приведен пример:
подводить итоги
Как видите, использование Serializable относительно просто, просто создайте номер версии; хотя Parcelable относительно сложен, необходимо реализовать четыре метода.
Как правило, рекомендуется использовать Serializable при сохранении данных на SD-карту или передаче по сети.Хотя эффективность ниже, им легко пользоваться.
Рекомендуется использовать Parcelable для передачи данных во время выполнения, например Intent, Bundle и т. Д. Нижний уровень Android оптимизирован для обеспечения высокой эффективности.
Thanks
Перевод с: https://blog.csdn.net/u011240877/article/details/72455715
1. Что такое сериализация и десериализация?
(1) Объяснение терминов
Сериализация объекта: процесс преобразования объекта Java в байтовую последовательность и сохранения его на носителе.
Десериализация объектов: процесс восстановления последовательностей байтов в объекты Java.
(2) Подробное объяснение сериализации
Сериализация объектов включает три ключевых момента: объекты Java, последовательности байтов и хранилище.
1. Каков состав объектов Java?
Объекты Java содержат переменные и методы. Но сериализация и десериализация имеют дело только с переменными Java, а не с методами, а сериализация и десериализация имеют дело только с данными.
2. Что такое последовательность символов?
Последовательность символов состоит из двух слов, символ находится в поле компьютера и связи, а символ является единицей информации. Математически последовательность — это объект (или событие), расположенный в ряд.
«Персонажи-Википедия» ,«Последовательность-Википедия»Грубо говоря, это набор из нескольких последовательно расположенных персонажей. Похожие на «1A165613246546»
3. Магазин
Последовательность символов необходимо сохранить в одном месте, которым может быть жесткий диск или память.
Проще говоря: сериализация сохраняет информацию о текущем объекте. Десериализация — прямо противоположная операция.
Во-вторых, чем отличается Java-объект от сериализации Java-объекта?
Предпосылка для существования объектов Java должна существовать во время работы JVM.Если вы хотите получить указанный объект Java, когда JVM не запущена или на JVM другой машины, это невозможно выполнить в рамках существующего механизма объектов Java.
В отличие от объектов Java, если вы выполняете операции сериализации над объектами Java, поскольку принцип заключается в сохранении информации об объекте Java на носителе, вы можете использовать два типа объектов Java, которые не могут существовать. В этом случае объекты Java все еще можно использовать.
3. Зачем использовать сериализацию и десериализацию?
Основываясь на вышеупомянутом понимании сериализации и десериализации, этот вопрос можно перевести на вопрос: почему мне нужно сохранять информацию об объекте на носителе данных и читать ее позже?
Из-за объяснения во втором случае необходимо получить указанный объект Java, когда JVM не запущена или на JVM других машин.
1. Используйте RMI (удаленный вызов метода)
2. Передача объектов в сети (Java Beans)
3. Глубокая копия объекта (включая сеть отношений между объектами, содержащуюся в текущем объекте)
4. В чем разница между Serializable и Parcelable в Android?
Оба используются для поддержки операций сериализации и десериализации. Самая большая разница между ними — это разница в носителях. Serializable использует ввод-вывод для чтения, записи и хранения на жестком диске, тогда как Parcelable читает и записывает непосредственно в память. Очевидно, что память Скорость чтения и записи обычно выше, чем у ввода-вывода, поэтому в Android обычно предпочтительнее использовать Parcelable.
Сериализуемость не в центре внимания, но вы можете проверить«Анализ алгоритмов сериализации Java»В этой статье реализован простой пример Serializable: просмотрите файл ввода-вывода, сгенерированный сериализацией, прочтите его в шестнадцатеричном формате и по очереди объясните значение каждого шестнадцатеричного числа.
Пять, пример Parcelable
Класс, реализующий интерфейс Parcelable в Android, может поддерживать последовательность и десериализацию. Ниже приведен пример реализации:
1. Реализуйте интерфейс Parcelable.
2. Добавьте атрибуты сущности
3. Переопределите метод writeToParcel (Parcel dest, int flags), чтобы указать данные, которые будут записаны в класс Parcel.
4. Создайте статический объект Parcelable.Creator, есть два метода createFromParcel (Parcel in) и newArray (int size), первый указывает, как читать объекты данных из Parcel, второй создает Массив.
5. Переопределите метод describeContents и верните 0 по умолчанию.
public class Gril implements Parcelable <
private int mAge; // возраст
private boolean mSexy; // Это сексуально
public void writeToParcel(Parcel dest, int flags) <
dest.writeByte((byte) (mSexy ? 1 : 0));
public static final Parcelable.Creator CREATOR = new Parcelable.Creator () <
public Gril createFromParcel(Parcel in) <
Gril gril = new Gril();
gril.mSexy = in.readByte() != 0;
public Gril[] newArray(int size) <
return new Gril[size];
public int describeContents() <
Шесть, принцип посылки
Как видно из приведенного выше примера, конкретная запись (dest.writeInt (mAge);) и чтение (gril.mAge = in.readInt ();) — это все операции, выполняемые над объектом Parcel, опубликованным ниже. Это определение Parcle для чтения и записи данных типа int.
public final class Parcel <
* Write an integer value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
public final native void writeInt(int val);
* Read an integer value from the parcel at the current dataPosition().
public final native int readInt();
Из приведенного выше кода видно, что все описания собственных методов используют JNI, а конкретное местоположение — system / frameworks / base / core / jni / android_util_Binder.cpp. Далее также в качестве примера используется чтение и запись типа int.
static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val)
Parcel* parcel = parcelForJavaObject(env, clazz);
if (parcel != NULL) <
const status_t err = parcel->writeInt32(val);
if (err != NO_ERROR) <
jniThrowException(env, «java/lang/OutOfMemoryError», NULL);
static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz)
Parcel* parcel = parcelForJavaObject(env, clazz);
if (parcel != NULL) <
Из вышеизложенного видно, что вызывается реализация Parcel и вызываются функции writeInt32 и readInt32 соответственно, а затем давайте посмотрим на конкретную реализацию. Расположение: /system/frameworks/base/libs/binder/Parcel.cpp
status_t Parcel::writeInt32(int32_t val)
status_t Parcel::writeAligned(T val) <
*reinterpret_cast (mData+mDataPos) = val;
status_t err = growData(sizeof(val));
if (err == NO_ERROR) goto restart_write;
status_t Parcel::readInt32(int32_t *pArg) const
status_t Parcel::readAligned(T *pArg) const <
const void* data = mData+mDataPos;
*pArg = *reinterpret_cast (data);
Следующие 4 балла взяты из«Изучение механизма отправки посылок в Android (часть 1)»
Заинтересованные друзья могут прочитать его сами. Это несложно понять. Вот краткое изложение основных идей:
1. Все чтение и запись выполняются в памяти, в основном с помощью malloc (), realloc (), memcpy () и других операций с памятью, поэтому это более эффективно, чем использование external в сериализации JAVA. Память будет намного выше;
2. При чтении и записи он выравнивается по 4 байтам, вы можете видеть, что #define PAD_SIZE (s) (((s) +3) &
3) выполняет определение макроса это дело;
3. Если предварительно выделенного места недостаточно, newSize = ((mDataSize + len) * 3) / 2; сразу выделит на 50% больше;
4. Для обычных данных используется адрес памяти mData, а для данных типа IBinder и FileDescriptor используется адрес памяти mObjects. Последнее достигается с помощью flatten_binder () и unflatten_binder (), цель состоит в том, что объект, прочитанный во время десериализации, является исходным объектом без необходимости обновлять новый объект.
Семь, сериализация и десериализация Parcelable эксперимент?
Источник