Урок 14: Интерфейс Serializable – передача данных между Activity

14 1 scaled - Android [Kotlin] для начинающих

Смотрите видеоурок бесплатно на удобной для вас платформе:

Введение

На предыдущем уроке мы узнали что такое объект Intent, как с помощью него осуществлять открытие нового Activity и передавать простые типы данных. Это база, так что если не смотрели, обязательно начните с предыдущего видео. Продолжаем тему и переходим к самому интересному – передаче объектов между Activity.

Рассматривать будем прямые способы передачи данных с помощью интерфейсов Serializable и Parcelable, а также специального класса Bundle.

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

Создам объект слова с рандомными данными. Наша задача будет передать его во вторую Активити и отобразить одно из его свойств в уже созданную View с айдишником tvText.

val word = ExtraWord(
    "galaxy",
    "галактика",
)

Попробую передать объект с использованием putExtra, также прописываю уникальный ключ и вижу ошибку. Наводим курсор и видим список валидных типов. Все значения вам должны быть знакомы за исключением трех.

image - Android [Kotlin] для начинающих

Это как раз то, что позволит нам передавать именно объекты.

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

Обратный процесс сериализации – это десериализация. То есть процесс восстановления объектов из их сериализованного представления. Теперь подробнее о каждом из них.

Интерфейс Serializable в Kotlin / Android

Интерфейс Serializable — классический способ сериализации объектов в Java. Этот интерфейс не имеет методов, но он указывает JVM, что объекты этого класса могут быть сериализованы. Он работает, создавая копию объекта в памяти и затем записывая эту копию в байтовый поток. Serializable обычно используется в случаях, когда требуется сериализация объектов, которые содержат небольшой объем данных.

Под небольшим объемом данных имею в виду как раз объекты с несколькими свойствами, типа слова, как у нас. Или, например, часто встречающийся объект User с набором свойств типа id, name и так далее.

Как отправить Serializable объект

Чтобы объект можно было отправить через Extra – необходимо наследовать класс от интерфейса Serializable. Это все, что нужно сделать. Как видим ошибка пропала.

data class ExtraWord(
    val original: String,
    val translate: String,
    var learned: Boolean = false,
) : Serializable

Еще раз, что здесь происходит:

  1. Вызываем putExtra() и передаем данные в виде пары ключ-значение.
  2. Внутри Intent‘a создается (или используется существующий) объект Bundle. Bundle — это контейнер для хранения данных. Он может сохранять как примитивные типы (например, строки и числа), так и сериализованные объекты (которые реализуют либо Serializable, либо Parcelable). Напомню, на прошлом уроке мы смотрели сигнатуру метода putExtra() и убедились, что под капотом метода используется Bundle.
  3. Далее, если объект реализует один из этих интерфейсов (как сейчас), он сериализуется (то есть преобразуется в поток байтов) и добавляется в Bundle.

Как получить Serializable объект

Получение Serializable с помощью intent.getSerializableExtra

Чтобы получить объект также обращаюсь к проперти intent и вызываю метод getSerializableExtra.

image 1 - Android [Kotlin] для начинающих

Смотрите, здесь два одинаковых метода с разной сигнатурой. Первый включает два параметра, где вторым параметром уточняется тип передаваемого объекта. Нам нужен именно он. Это более свежая версия метода, сейчас вы поймете как использовать их оба.

Вписываю ключ, по которому нужно получить объект из интента, а вторым параметром указываем ссылку на data class нашего слова. Причем через контекстное меню можно выполнить импорт класса в файл, чтобы сократить код и оставить только его название.

intent.getSerializableExtra("EXTRA_KEY_WORD", ExtraWord::class.java)

Все хорошо, но метод подсвечивается красным. Call requires API level 33 (current min is 26) говорит о том, что этот метод актуален для версии API от 33. А в настройках градл у нас минимально поддерживаемая версия на момент записи ролика стоит 26.

Студия предлагает повесить аннотацию, мол требуется версия Тирамису. Но от этого на устройствах с API до 33 версии все равно ничего работать не будет. Нам нужен второй deprecated метод, который не требует второго параметра с уточнением передаваемого класса. Продублирую его здесь для наглядности и добавлю переменные, чтобы посмотреть на тип, который будет в них приходить.

intent.getSerializableExtra("EXTRA_KEY_WORD", ExtraWord::class.java)
intent.getSerializableExtra("EXTRA_KEY_WORD") // deprecated

Как видим устаревший метод возвращает тип Serializable, который нужно самостоятельно привести к требуемому типу. И это небезопасное приведение типа.

В другом методе благодаря тому, что мы передаем в качестве второго параметра класс – метод автоматически делает приведение к нужному типу. Тем самым гарантируя безопасность.

Но как убрать ошибку? Мы можем проверять текущую версию API операционной системы и в зависимости от нее вызывать нужный метод получения объекта. Вызываем контекстное меню и добавляем условие проверки текущей версии SDK.

%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0_2024-09-06_%D0%B2_17.05.49.png

И в else будет запускаться код на устройствах ниже версии TIRAMISU. Можно перейти в переменную и убедиться, что это 33 версия API. Сюда переносим deprecated функцию чтения Extra. Причем она возвращает тип Serializable?, тем самым теперь переменная word стала с таким же типом. Поэтому в конце везде нужно выполнить ручное приведение типа к нужному нам ненулябельному классу с помощью ключевого слова as.

val word: ExtraWord = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    intent.getSerializableExtra("EXTRA_KEY_WORD", ExtraWord::class.java) as ExtraWord
} else {
    intent.getSerializableExtra("EXTRA_KEY_WORD") as ExtraWord
}

Получение Serializable с помощью intent.extras?.getSerializable

Есть еще пара форм записей обращения к экстра у интента. Например, можно обратиться к проперти extras (бывший метод getExtras()), затем вызвать getSerializable(). Тот же самый принцип работы, только это метод класса Bundle. А getSerializableExtra() располагается в классе Intent. Вот и вся разница.

val word2 = intent.extras?.getSerializable("EXTRA_KEY_WORD", ExtraWord::class.java)

Получение Serializable с помощью intent.extras?.get

Ну или вы можете встретить совсем древний метод get, который возвращает Any и также надо было руками приводить переданные данные к требуемому типу.

val word3 = intent.extras?.get("EXTRA_KEY_WORD")

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

Все, мне остается только добавить TextView для выводимого слова. Свойств в объекте несколько, но я ограничусь просто выводом оригинального слова. Сам факт передачи объекта таким образом на новый экран полагаю должен быть понятен. Обращаюсь к объекту и к свойству original. Запускаем и проверяем вывод.

Проблемы с производительностью у Serializable

Резюмируя можно сказать, что это действительно простой и удобный способ передачи простых структур данных. Однако, для сложных объектов Serializable не очень подходит и вот почему:

  • Serializable использует стандартную Java-сериализацию, которая преобразует объект в поток байтов через механизм рефлексии. Это делает его относительно медленным, за счет того, что JVM (Java Virtual Machine) анализирует объект на лету .
  • Serializable также создает множество временных объектов в процессе сериализации, что может приводить к повышенному расходу памяти, особенно на устройствах с ограниченными ресурсами.

Для тех, кто собрался стать Android-разработчиком

Пошаговаясхема
Пошаговая
схема

Описание процесса обучения от основ Kotlin до Android-разработчика

Бесплатныеуроки
Бесплатные
уроки

Авторский бесплатный курс по основам языка программирования Kotlin

Обучающийбот
Обучающий
бот

Тренажер и самоучитель по Котлин – бесплатные тесты и практика

Поделиться уроком

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *