Сериализацията и десериализацията са фундаментални процеси за преобразуване на обекти във формат за предаване или съхранение. В мобилното разработване тези механизми се използват при всяка мрежова заявка, запазване на състояние и междупроцесна комуникация. Според MDN Web Docs, 2024, JSON остава най-популярният формат за сериализация в уеб и мобилни приложения, изпреварвайки XML и Protocol Buffers.
Основни точки
Сериализация е процесът на преобразуване на обекта на приложението във формат, подходящ за изпращане по мрежа или записване на диск. Десериализацията извършва обратното преобразуване, възстановявайки обекта от получените данни. В мобилното разработване сериализацията се прилага в API заявки, запазване на състояние на екрана, кеширане и предаване на данни чрез Intent или Bundle.
Всяко взаимодействие между компонентите на приложението или между приложението и сървъра изисква сериализация. REST API предават данни в JSON или XML, gRPC използва Protocol Buffers, а вътрешнопроцесната комуникация на Android използва Parcelable. Без сериализация е невъзможно да се предаде сложен обект през границата на процеса или да се запази в базата данни.
// Общ принцип на сериализацията
data class User(
val id: Int,
val name: String,
val email: String
)
// Сериализация: обект -> JSON
fun serializeUser(user: User): String {
return """{"id":${user.id},"name":"${user.name}","email":"${user.email}"}"""
}
// Десериализация: JSON -> обект
fun deserializeUser(json: String): User? {
// парсване на JSON в обект
return Gson().fromJson(json, User::class.java)
}
| Формат | Размер | Скорост | Четимост | Типизация |
|---|---|---|---|---|
| JSON | среден | висока | висока | динамична |
| XML | голям | средна | висока | схема XSD |
| Protocol Buffers | малък | много висока | ниска | строг .proto |
| FlatBuffers | малък | максимална | ниска | строг .fbs |
JSON (JavaScript Object Notation) e лек текстов формат, базиран на синтаксиса на JavaScript обектите. JSON поддържа низове, числа, булеви стойности, масиви и вложени обекти, което покрива повечето сценарии за предаване на данни в мобилните приложения. Форматът е независим от платформата: всяка екосистема предоставя вградени инструменти за неговото парсване.
JSON печели благодарение на своята простота и универсалност. Разработчикът не се нуждае от схема за основна употреба — структурата се определя динамично по време на парсване. Четимостта на формата опростява отстраняването на грешки и тестването: отговорът на сървъра може да се види във всеки инструмент за разработчици. На двете мобилни платформи JSON се обработва нативно без свързване на външни библиотеки.
// Codable — естествена JSON сериализация в Swift
struct User: Codable {
let id: Int
let name: String
let email: String
}
let jsonString = """{"id":1,"name":"John","email":"john@test.com"}"""
let jsonData = Data(jsonString.utf8)
let decoder = JSONDecoder()
let user = try! decoder.decode(User.self, from: jsonData)
Protocol Buffers (protobuf) е двоичен формат за сериализация, разработен от Google за високопроизводителни системи. За разлика от JSON, protobuf изисква предварително дефиниране на схема в .proto файл, но осигурява значително по-малък размер на данните и по-висока скорост на обработка. Форматът се използва в gRPC, Firebase Firestore и вътрешните услуги на Google.
Схемата protobuf описва съобщения с типизирани полета, всяко от които има уникален номер. Компилаторът protoc генерира класове на желания език, които автоматично извършват сериализация и десериализация. Protobuf поддържа еволюция на схемата чрез правила за добавяне и премахване на полета без загуба на обратна съвместимост.
// Дефиниране на схема в user.proto
syntax = "proto3";
message User {
int32 id = 1;
string name = 2;
string email = 3;
repeated string roles = 4;
}
// Генериран код на Kotlin
val user = UserProto.User.newBuilder()
.setId(1)
.setName("John")
.setEmail("john@test.com")
.build()
val bytes: ByteArray = user.toByteArray()
XML (eXtensible Markup Language) е формат със строга структура, поддръжка на именни пространства и валидиране чрез XSD схеми. XML губи спрямо JSON по отношение на компактност и скорост на парсване, но остава търсен в разработката за Android за файлове с оформление, AndroidManifest, ресурси и Gradle конфигурации. На iOS XML се използва в plist файлове и някои по-стари услуги.
Android предлага три начина за парсване на XML: DOM (зареждане на целия документ в паметта), SAX (събитийно-ориентирано поточно парсване) и XmlPullParser (хибриден подход). XmlPullParser е препоръчителният вариант за мобилни устройства, тъй като работи ефективно с ограничена памет и позволява обработка на документа по време на четене.
// XmlPullParser на Android
fun parseUserXml(inputStream: InputStream): User? {
val parser = Xml.newPullParser()
parser.setInput(inputStream, Xml.Encoding.UTF_8.name)
var id: Int? = null
var name: String? = null
var email: String? = null
while (parser.next() != XmlPullParser.END_DOCUMENT) {
if (parser.eventType == XmlPullParser.START_TAG
&& parser.name == "email") {
email = parser.nextText()
}
}
return User(id!!, name!!, email!!)
}
Всяка платформа предлага свои собствени инструменти за сериализация. На iOS основният механизъм е протоколът Codable с JSONEncoder и JSONDecoder, а за Objective-C — NSJSONSerialization. Android използва библиотеките Gson, Moshi и kotlinx.serialization. За предаване на данни между процеси Android използва Parcelable, а iOS — NSKeyedArchiver. Kotlin проектите все по-често избират kotlinx.serialization — решение на JetBrains, което поддържа мултиплатформеност и не зависи от рефлексия, генерирайки сериализатори на етапа на компилация чрез плъгин на компилатора Kotlin.
Android поддържа два механизма за сериализация за Intent и Bundle. Serializable е стандартният Java механизъм, който използва рефлексия, което води до ниска производителност. Parcelable е специфичен за Android протокол, който изисква ръчно имплементиране на методите writeToParcel и createFromParcel, но работи десетки пъти по-бързо благодарение на директно манипулиране на байтове.
// Parcelable на Android
@Parcelize
data class UserParcel(
val id: Int,
val name: String,
val email: String
) : Parcelable
// Предаване чрез Intent
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("user", userParcel)
startActivity(intent)
На iOS за предаване на данни между контролери се използва Codable с предварителна сериализация в Data, а за междупроцесна комуникация — NSKeyedArchiver, който преобразува обекти в двоичен формат Property List. Съвременните проекти в SwiftUI предпочитат кодирането на данни чрез JSONEncoder за предаване между модулите на приложението.
Неправилната десериализация на недоверени данни може да доведе до уязвимости. Атаки чрез сериализация експлоатират презаписани методи readObject в Java или несигурни десериализатори на външни библиотеки. На Android трябва да се избягва Serializable за данни от недоверени източници, като вместо това се използва Parcelable или ръчно валидиране на всички полета след десериализация. На iOS JSONDecoder е по подразбиране строг към типовете, но при работа с JSONSerialization разработчикът трябва да проверява типовете чрез условно преобразуване.
При избора на формат за сериализация се вземат предвид изискванията за производителност, размер на данните и съвместимост. За REST API и микроуслужна архитектура оптималният избор остава JSON — поддържа се от всички платформи и езици. За високонатоварени системи и мобилни приложения с ограничен трафик се предпочитат Protocol Buffers, които осигуряват по-малък размер и по-бърза десериализация. XML е оправдан само в конфигурационни сценарии и при интеграция с наследени системи. В съвременните проекти FlatBuffers също набира популярност — двоичен формат без етап на десериализация, използван в игрови двигатели и приложения с минимално закъснение. Всеки формат има своя ниша и правилният избор пряко влияе върху скоростта на работа на приложението и обема на консумирания трафик.
Често задавани въпроси
Сериализация е опаковане на обекта на приложението във формат, който може да бъде изпратен по мрежа или запазен във файл. Представете си, че снимате предмет — снимката е сериализация, а възстановяването на предмета от снимката е десериализация.
JSON е текстов формат, четим за човека и не изисква схема. Protocol Buffers е двоичен формат със задължителна схема (.proto), значително по-малък размер и по-висока скорост. Protobuf се избира за високонатоварени системи, JSON — за универсална съвместимост.
XML остава стандарт за конфигурационни файлове (AndroidManifest, ресурси за оформление), документи със сложна вложеност и системи със строго валидиране чрез XSD. XML се прилага също в SOAP протоколи и наследени системи, където се изисква поддръжка на именни пространства.
Codable е протокол на Swift, който обединява Encodable и Decodable за автоматична сериализация и десериализация. Компилаторът генерира имплементация на методите encode(to:) и init(from:) за всички свойства на структурата или класа.
Parcelable работи значително по-бързо от Serializable, тъй като не използва рефлексия и директно записва полетата в байтов поток. На съвременните устройства разликата може да достигне 10-кратно ускорение в полза на Parcelable.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също