Serialization và deserialization là các quá trình cơ bản chuyển đổi đối tượng thành định dạng để truyền tải hoặc lưu trữ. Trong phát triển di động, các cơ chế này được sử dụng trong mọi yêu cầu mạng, lưu trạng thái và giao tiếp giữa các tiến trình. Theo MDN Web Docs, 2024, JSON vẫn là định dạng phổ biến nhất cho serialization trên web và trong các ứng dụng di động, vượt qua XML và Protocol Buffers.
Những điểm chính
Serialization là quá trình chuyển đổi đối tượng ứng dụng thành định dạng phù hợp để truyền qua mạng hoặc lưu trữ trên đĩa. Deserialization thực hiện chuyển đổi ngược lại, khôi phục đối tượng từ dữ liệu nhận được. Trong phát triển di động, serialization được sử dụng trong các yêu cầu API, lưu trạng thái màn hình, bộ nhớ đệm và truyền dữ liệu qua Intent hoặc Bundle.
Bất kỳ tương tác nào giữa các thành phần ứng dụng hoặc giữa ứng dụng và máy chủ đều yêu cầu serialization. API REST truyền dữ liệu ở định dạng JSON hoặc XML, gRPC sử dụng Protocol Buffers và giao tiếp nội bộ tiến trình trên Android sử dụng Parcelable. Nếu không có serialization, không thể truyền một đối tượng phức tạp qua ranh giới tiến trình hoặc lưu nó vào cơ sở dữ liệu.
// Nguyên tắc chung của serialization
data class User(
val id: Int,
val name: String,
val email: String
)
// Serialization: đối tượng -> JSON
fun serializeUser(user: User): String {
return """{"id":${user.id},"name":"${user.name}","email":"${user.email}"}"""
}
// Deserialization: JSON -> đối tượng
fun deserializeUser(json: String): User? {
// phân tích JSON thành đối tượng
return Gson().fromJson(json, User::class.java)
}
| Định dạng | Kích thước | Tốc độ | Khả năng đọc | Kiểu |
|---|---|---|---|---|
| JSON | trung bình | cao | cao | động |
| XML | lớn | trung bình | cao | lược đồ XSD |
| Protocol Buffers | nhỏ | rất cao | thấp | nghiêm ngặt .proto |
| FlatBuffers | nhỏ | tối đa | thấp | nghiêm ngặt .fbs |
JSON (JavaScript Object Notation) là định dạng văn bản nhẹ dựa trên cú pháp đối tượng JavaScript. JSON hỗ trợ chuỗi, số, giá trị boolean, mảng và đối tượng lồng nhau, bao phủ hầu hết các kịch bản truyền dữ liệu trong ứng dụng di động. Định dạng độc lập với nền tảng: mỗi hệ sinh thái cung cấp các công cụ tích hợp để phân tích cú pháp.
JSON chiến thắng nhờ sự đơn giản và linh hoạt. Nhà phát triển không cần lược đồ cho việc sử dụng cơ bản — cấu trúc được xác định động trong quá trình phân tích. Khả năng đọc của định dạng đơn giản hóa việc gỡ lỗi và kiểm tra: phản hồi từ máy chủ có thể được xem trong bất kỳ công cụ phát triển nào. Trên cả hai nền tảng di động, JSON được xử lý tự nhiên mà không cần thư viện bên thứ ba.
// Codable — serialization JSON gốc trong 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) là định dạng serialization nhị phân được Google phát triển cho các hệ thống hiệu suất cao. Không giống như JSON, protobuf yêu cầu lược đồ được xác định trước trong tệp .proto, nhưng cung cấp kích thước dữ liệu nhỏ hơn đáng kể và tốc độ xử lý cao hơn. Định dạng này được sử dụng trong gRPC, Firebase Firestore và các dịch vụ nội bộ của Google.
Lược đồ protobuf mô tả các thông điệp với các trường được định kiểu, mỗi trường có một số duy nhất. Trình biên dịch protoc tạo ra các lớp trong ngôn ngữ đích thực hiện serialization và deserialization tự động. Protobuf hỗ trợ tiến hóa lược đồ thông qua các quy tắc thêm và xóa trường mà không mất khả năng tương thích ngược.
// Định nghĩa lược đồ trong user.proto
syntax = "proto3";
message User {
int32 id = 1;
string name = 2;
string email = 3;
repeated string roles = 4;
}
// Mã được tạo trong Kotlin
val user = UserProto.User.newBuilder()
.setId(1)
.setName("John")
.setEmail("john@test.com")
.build()
val bytes: ByteArray = user.toByteArray()
XML (eXtensible Markup Language) là định dạng với cấu trúc cứng nhắc, hỗ trợ không gian tên và xác thực qua lược đồ XSD. XML thua kém JSON về tính nhỏ gọn và tốc độ phân tích, nhưng vẫn được yêu cầu trong phát triển Android cho các tệp bố cục, AndroidManifest, tài nguyên và cấu hình Gradle. Trên iOS, XML được sử dụng trong các tệp plist và một số dịch vụ kế thừa.
Android cung cấp ba phương pháp phân tích XML: DOM (tải toàn bộ tài liệu vào bộ nhớ), SAX (phân tích luồng dựa trên sự kiện) và XmlPullParser (phương pháp kết hợp). XmlPullParser là lựa chọn được khuyến nghị cho thiết bị di động, vì nó hoạt động hiệu quả với bộ nhớ hạn chế và cho phép xử lý tài liệu trong khi đọc.
// XmlPullParser trên 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!!)
}
Mỗi nền tảng cung cấp các công cụ serialization riêng. Trên iOS, cơ chế chính là giao thức Codable với JSONEncoder và JSONDecoder, trong khi Objective-C sử dụng NSJSONSerialization. Android sử dụng các thư viện Gson, Moshi và kotlinx.serialization. Để truyền dữ liệu giữa các tiến trình, Android sử dụng Parcelable, trong khi iOS sử dụng NSKeyedArchiver. Các dự án Kotlin ngày càng chọn kotlinx.serialization — một giải pháp của JetBrains hỗ trợ đa nền tảng và không phụ thuộc vào phản xạ, tạo ra các bộ serialization tại thời điểm biên dịch thông qua plugin trình biên dịch Kotlin.
Android hỗ trợ hai cơ chế serialization cho Intent và Bundle. Serializable là cơ chế Java tiêu chuẩn sử dụng phản xạ, dẫn đến hiệu suất thấp hơn. Parcelable là giao thức dành riêng cho Android yêu cầu triển khai thủ công các phương thức writeToParcel và createFromParcel, nhưng hoạt động nhanh hơn hàng chục lần nhờ thao tác trực tiếp với byte.
// Parcelable trên Android
@Parcelize
data class UserParcel(
val id: Int,
val name: String,
val email: String
) : Parcelable
// Truyền qua Intent
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("user", userParcel)
startActivity(intent)
Trên iOS, Codable với serialization sơ bộ thành Data được sử dụng để truyền dữ liệu giữa các bộ điều khiển, trong khi NSKeyedArchiver được sử dụng cho giao tiếp giữa các tiến trình, chuyển đổi đối tượng thành định dạng Property List nhị phân. Các dự án SwiftUI hiện đại thích mã hóa dữ liệu qua JSONEncoder để truyền giữa các mô-đun ứng dụng.
Việc deserialization không đúng cách dữ liệu không đáng tin cậy có thể dẫn đến lỗ hổng bảo mật. Các cuộc tấn công qua serialization khai thác các phương thức readObject bị ghi đè trong Java hoặc các bộ deserialization không an toàn từ thư viện bên thứ ba. Trên Android, nên tránh Serializable cho dữ liệu từ nguồn không đáng tin cậy, thay vào đó sử dụng Parcelable hoặc xác thực thủ công tất cả các trường sau khi deserialization. Trên iOS, JSONDecoder mặc định nghiêm ngặt với các kiểu, nhưng khi làm việc với JSONSerialization, nhà phát triển phải kiểm tra kiểu thông qua ép kiểu có điều kiện.
Khi chọn định dạng serialization, các yêu cầu về hiệu suất, kích thước dữ liệu và khả năng tương thích được xem xét. Đối với API REST và kiến trúc microservice, JSON vẫn là lựa chọn tối ưu — nó được hỗ trợ bởi tất cả nền tảng và ngôn ngữ. Đối với hệ thống tải cao và ứng dụng di động có băng thông hạn chế, Protocol Buffers được ưa chuộng hơn, cung cấp kích thước nhỏ hơn và deserialization nhanh hơn. XML chỉ hợp lý trong các kịch bản cấu hình và khi tích hợp với hệ thống kế thừa. Các dự án hiện đại cũng đang chứng kiến sự gia tăng của FlatBuffers — định dạng nhị phân không có bước deserialization, được sử dụng trong các công cụ trò chơi và ứng dụng có độ trễ tối thiểu. Mỗi định dạng có lĩnh vực riêng và lựa chọn đúng đắn ảnh hưởng trực tiếp đến tốc độ ứng dụng và lưu lượng tiêu thụ.
Câu hỏi thường gặp
Serialization là đóng gói một đối tượng ứng dụng thành định dạng có thể gửi qua mạng hoặc lưu vào tệp. Hãy tưởng tượng bạn chụp ảnh một vật thể — bức ảnh là serialization và khôi phục vật thể từ bức ảnh là deserialization.
JSON là định dạng văn bản có thể đọc được và không yêu cầu lược đồ. Protocol Buffers là định dạng nhị phân với lược đồ bắt buộc (.proto), kích thước nhỏ hơn đáng kể và tốc độ cao hơn. Protobuf được chọn cho hệ thống tải cao, JSON được chọn cho khả năng tương thích phổ quát.
XML vẫn là tiêu chuẩn cho tệp cấu hình (AndroidManifest, tài nguyên bố cục), tài liệu có cấu trúc lồng nhau phức tạp và hệ thống có xác thực nghiêm ngặt qua XSD. XML cũng được sử dụng trong giao thức SOAP và hệ thống kế thừa yêu cầu hỗ trợ không gian tên.
Codable là giao thức Swift kết hợp Encodable và Decodable để tự động serialization và deserialization. Trình biên dịch tạo ra triển khai các phương thức encode(to:) và init(from:) cho tất cả thuộc tính của cấu trúc hoặc lớp.
Parcelable hoạt động nhanh hơn đáng kể so với Serializable vì nó không sử dụng phản xạ và ghi trực tiếp các trường vào luồng byte. Trên các thiết bị hiện đại, sự khác biệt có thể lên tới 10 lần nghiêng về Parcelable.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm