В этом уроке:

- знакомимся с 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:

package ru.startandroid.develop.p0681parcel;

import android.app.Activity;
import android.os.Bundle;
import android.os.Parcel;
import android.util.Log;

public class MainActivity extends Activity {

  final String LOG_TAG = "myLogs";
  Parcel p;

  /** Called when the activity is first created. */
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    writeParcel();
    readParcel();
  }

  void writeParcel() {
    p = Parcel.obtain();

    byte b = 1;
    int i = 2;
    long l = 3;
    float f = 4;
    double d = 5;
    String s = "abcdefgh";

    logWriteInfo("before writing");
    p.writeByte(b);
    logWriteInfo("byte");
    p.writeInt(i);
    logWriteInfo("int");
    p.writeLong(l);
    logWriteInfo("long");
    p.writeFloat(f);
    logWriteInfo("float");
    p.writeDouble(d);
    logWriteInfo("double");
    p.writeString(s);
    logWriteInfo("String");
  }

  void logWriteInfo(String txt) {
    Log.d(LOG_TAG, txt + ": " + "dataSize = " + p.dataSize());
  }

  void readParcel() {
  }

  void logReadInfo(String txt) {
  }

}

 

Метод 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 под каждый символ использует два байта, но пишет еще служебную информацию, поэтому получается больше.

 

Теперь попробуем прочесть то, что записали. Заполним пустые методы чтения:

  void readParcel() {
    logReadInfo("before reading");
    p.setDataPosition(0);
    logReadInfo("byte = " + p.readByte());
    logReadInfo("int = " + p.readInt());
    logReadInfo("long = " + p.readLong());
    logReadInfo("float = " + p.readFloat());
    logReadInfo("double = " + p.readDouble());
    logReadInfo("string = " + p.readString());
  }

  void logReadInfo(String txt) {
    Log.d(LOG_TAG, txt + ": " + "dataPosition = " + p.dataPosition());
  } 

В методе 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, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня




Language

Автор сайта

Дмитрий Виноградов

Подробнее можно посмотреть или почитать.

Никакие другие люди не имеют к этому сайту никакого отношения и просто занимаются плагиатом.

Социальные сети

 

В канале я публикую ссылки на интересные и полезные статьи по Android

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



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal