การจัดเก็บข้อมูลถาวรช่วยรักษาข้อมูลผู้ใช้ระหว่างเซสชันการทำงานของแอปพลิเคชันมือถือ หากไม่มีเทคโนโลยีนี้ ทุกครั้งที่เปิดโปรแกรมจะเริ่มต้นจากศูนย์ — การตั้งค่า ประวัติ และไฟล์ที่ดาวน์โหลดมาจะหายไปเมื่อปิดแอป ตามข้อมูลจาก Google Developers, 2024 พบว่า กว่า 90% ของแอปพลิเคชันมือถือ ใช้กลไกการจัดเก็บข้อมูลถาวรอย่างน้อยหนึ่งรูปแบบเพื่อบันทึกข้อมูลผู้ใช้และสถานะอินเทอร์เฟซ
สาระสำคัญ
Data Persistence คือความสามารถของแอปพลิเคชันในการบันทึกข้อมูลลงในหน่วยความจำที่ไม่ถูกลบเมื่อปิดเครื่อง ในการพัฒนามือถือ การจัดเก็บข้อมูลถาวรครอบคลุมฐานข้อมูล ระบบไฟล์ การตั้งค่า และแคช แต่ละกลไกมีคุณสมบัติด้านประสิทธิภาพ ความปลอดภัย และปริมาณข้อมูลที่จัดเก็บแตกต่างกัน
ข้อมูลชั่วคราวมีอยู่เฉพาะในหน่วยความจำและจะหายไปเมื่อสิ้นสุดกระบวนการ ซึ่งรวมถึงสถานะหน้าจอ การคำนวณชั่วคราว และแคชรูปภาพ ข้อมูลถาวร จะถูกเขียนลงในระบบไฟล์หรือฐานข้อมูลและยังคงเข้าถึงได้หลังจากรีสตาร์ทแอปพลิเคชัน ซึ่งรวมถึงการตั้งค่าผู้ใช้ โทเค็นการยืนยันตัวตน ประวัติการดำเนินการ และคอนเทนต์ที่ดาวน์โหลด
ในการเลือกวิธีการบันทึกข้อมูล นักพัฒนาจะประเมินปัจจัยหลายประการ ประเภทของข้อมูล กำหนดโครงสร้างการจัดเก็บ: การตั้งค่าอย่างง่ายใช้ SharedPreferences หรือ DataStore ข้อมูลที่มีโครงสร้างใช้ SQLite หรือ Room และไฟล์ใช้ File Storage ปริมาณข้อมูลมีผลต่อประสิทธิภาพ: ฐานข้อมูลถูกออกแบบมาสำหรับบันทึกนับพันรายการ ในขณะที่ไฟล์เหมาะสำหรับออบเจกต์ไบนารีขนาดใหญ่ ความปลอดภัยต้องการการเข้ารหัสข้อมูลที่ละเอียดอ่อนผ่าน EncryptedSharedPreferences หรือ SQLCipher
data class StorageOption(
name: String,
dataType: StorageType,
capacity: Long,
secure: Boolean
)
enum class StorageType {
KEY_VALUE,
RELATIONAL,
FILE
}
SharedPreferences — วิธีการดั้งเดิมในการจัดเก็บคู่คีย์-ค่าบน Android API นี้มีมาตั้งแต่เวอร์ชันแรกของแพลตฟอร์มและรองรับชนิดข้อมูลพื้นฐาน: สตริง ตัวเลข ค่าบูลีน ข้อมูลจะถูกเก็บในไฟล์ XML ในไดเรกทอรีส่วนตัวของแอปพลิเคชันและเข้าถึงได้เฉพาะกระบวนการของแอปนั้นเท่านั้น
Jetpack DataStore — ตัวแทนสมัยใหม่ของ SharedPreferences ที่สร้างขึ้นบน Kotlin Coroutines และ Flow DataStore มีสองรูปแบบ: Preferences DataStore สำหรับค่าอย่างง่าย และ Proto DataStore สำหรับออบเจกต์ที่ระบุชนิดได้ ซึ่งแตกต่างจาก SharedPreferences ตรงที่ DataStore รับประกันความสอดคล้องของข้อมูลเมื่อมีการเข้าถึงพร้อมกัน และรองรับการดำเนินการแบบอะซิงโครนัสโดยไม่บล็อกเธรดหลัก
// SharedPreferences — วิธีดั้งเดิม
val prefs = context
.getSharedPreferences("settings", Context.MODE_PRIVATE)
with (prefs.edit()) {
putString("username", "john_doe")
putInt("score", 1500)
apply()
}
// DataStore — วิธีการแบบอะซิงโครนัส
val settingsDataStore = context
.createDataStore("settings.pb")
val usernameFlow: Flow<String> = settingsDataStore
.data
.map { it[USERNAME_KEY] ?: "" }
บน iOS เทียบเท่ากับ SharedPreferences คือ UserDefaults — ระบบจัดเก็บค่าอย่างง่ายในรูปแบบ Property List UserDefaults ใช้การเข้าถึงแบบซิงโครนัสและเหมาะสำหรับข้อมูลการกำหนดค่าจำนวนเล็กน้อย แต่ไม่แนะนำสำหรับการจัดเก็บข้อมูลที่ละเอียดอ่อน
SQLite — ฐานข้อมูลเชิงสัมพันธ์แบบฝังตัวที่ทำงานภายในกระบวนการของแอปพลิเคชันโดยไม่ต้องใช้เซิร์ฟเวอร์แยกต่างหาก เป็นระบบจัดการฐานข้อมูลที่แพร่หลายที่สุดในการพัฒนามือถือ โดยถูกใช้งานเป็นค่าเริ่มต้นบนทั้งสองแพลตฟอร์ม Android รวม SQLite ไว้ใน SDK และ iOS รวมไว้ในไลบรารี libsqlite3 SQLite รองรับ SQL มาตรฐาน ธุรกรรม ดัชนี และทริกเกอร์
การทำงานกับ SQLite เริ่มต้นด้วยการสร้าง Schema ของฐานข้อมูล นักพัฒนากำหนดตาราง ฟิลด์ และชนิดข้อมูล จากนั้นดำเนินการแทรก อ่าน อัปเดต และลบ SQLiteOpenHelper บน Android จัดการการสร้างฐานข้อมูลและการย้าย版本 ในขณะที่บน iOS ใช้อินเทอร์เฟซ C หรือตัวห่อหุ้ม FMDB
// SQLiteOpenHelper บน Android
class DBHelper(context: Context) :
SQLiteOpenHelper(context, "app.db", null, 1) {
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("""
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
)
""")
}
fun insertUser(name: String, email: String) {
val db = writableDatabase
val values = ContentValues().apply {
put("name", name)
put("email", email)
}
db.insert("users", null, values)
}
}
| ชนิดข้อมูล | SharedPreferences | SQLite | ระบบไฟล์ |
|---|---|---|---|
| ประเภท | คีย์-ค่า | ฐานข้อมูลเชิงสัมพันธ์ | ไฟล์ไบนารี |
| ปริมาณ | หลายร้อยรายการ | หลายพันรายการ | พื้นที่ว่างที่มี |
| ประสิทธิภาพ | สูง | ปานกลาง | ขึ้นอยู่กับขนาด |
| การใช้งานทั่วไป | การตั้งค่า | ข้อมูลที่มีโครงสร้าง | รูปภาพ, วิดีโอ |
Room — ไลบรารีในชุด Jetpack ที่ให้ชั้น ORM บน SQLite Room ขจัดงานประจำในการเขียน SQL queries และ ContentValues โดยแทนที่ด้วย annotation และฟังก์ชัน Kotlin คอมไพเลอร์ของ Room สร้างการทำงานของ DAO (Data Access Object) ในขั้นตอนการ build ซึ่งช่วยขจัดข้อผิดพลาดในไวยากรณ์ SQL
ในการเชื่อมต่อ Room จำเป็นต้องเพิ่ม dependency kapt และ annotate คลาส Entity, อินเทอร์เฟซ DAO และคลาสฐานข้อมูล RoomDatabase ทำหน้าที่เป็นจุดเข้า: ผ่านมันจะได้รับ DAO และดำเนินการกับฐานข้อมูล Room รองรับ Flow สำหรับคำค้นหาแบบรีแอกทีฟ การย้าย Schema และการตรวจสอบคำค้นหาในขั้นตอนการคอมไพล์
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "full_name") val name: String,
@ColumnInfo val email: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): Flow<List<User>>
@Insert
suspend fun insert(user: User)
@Delete
suspend fun delete(user: User)
}
@Database(
entities = [User::class],
version = 1
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Core Data — เฟรมเวิร์กของ Apple สำหรับจัดการกราฟของออบเจกต์และบันทึกลงดิสก์ ซึ่งแตกต่างจาก Room ตรงที่ Core Data ไม่ทำงานกับตาราง แต่ทำงานกับออบเจกต์ที่มีการจัดการ (NSManagedObject) ซึ่งสร้างลำดับชั้นของความสัมพันธ์ Core Data รองรับการโหลดแบบขี้เกียจ การยกเลิกการเปลี่ยนแปลง และคำค้นหาที่ซับซ้อนผ่าน NSFetchRequest
พื้นฐานของ Core Data คือ Stack ที่ประกอบด้วยสามส่วน: Managed Context (NSManagedObjectContext), Persistent Store Coordinator (NSPersistentStoreCoordinator) และ Data Model (NSManagedObjectModel) NSPersistentContainer รวมทุกส่วนเป็นจุดเข้าเดียว ช่วยให้การตั้งค่าง่ายขึ้นสำหรับแอปพลิเคชันสมัยใหม่บน Swift
import CoreData
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "AppModel")
container.loadPersistentStores { _, error in
if let error = error {
fatalError("Failed: \(error)")
}
}
}
func saveUser(name: String, email: String) {
let context = container.viewContext
let user = User(context: context)
user.name = name
user.email = email
do {
try context.save()
} catch let error {
print("ข้อผิดพลาดในการบันทึก: \(error)")
}
}
}
การจัดเก็บไฟล์ (File Storage) ใช้สำหรับบันทึกรูปภาพ วิดีโอ และเอกสาร Android มีพื้นที่จัดเก็บภายใน (context.filesDir) — ส่วนตัวสำหรับแอปพลิเคชัน และพื้นที่จัดเก็บภายนอก (Environment.getExternalStorageDirectory) — ที่แอปอื่นเข้าถึงได้ ใน iOS ไฟล์จะถูกบันทึกในไดเรกทอรี Documents และ Library โดยที่ Library/Caches มีไว้สำหรับแคชที่ไม่ต้องสำรองไปยัง iCloud สำหรับการทำงานกับไฟล์ ทั้งสองแพลตฟอร์มมี File API และการดำเนินการสตรีมสำหรับอ่านและเขียน ไลบรารีสมัยใหม่อย่าง Coil และ SDWebImage เพิ่มชั้นแคชที่ผสมผสานการจัดเก็บไฟล์กับหน่วยความจำเพื่อประสิทธิภาพที่เหมาะสมที่สุด
บน Android ทางเลือกที่เทียบเท่ากับ Core Data ในด้านความซับซ้อนและฟังก์ชันการทำงานคือ Realm — ฐานข้อมูลเชิงวัตถุที่ทำงานกับโมเดลโดยตรงโดยไม่ต้องมีชั้น SQL Realm เร็วกว่า SQLite ในการดำเนินการอ่าน และรองรับ live-objects ที่อัปเดต UI โดยอัตโนมัติเมื่อข้อมูลเปลี่ยนแปลง
คำถามที่พบบ่อย
Data Persistence คือกลไกการบันทึกข้อมูลในหน่วยความจำที่ไม่ถูกลบของอุปกรณ์ เพื่อให้เข้าถึงข้อมูลได้หลังจากรีสตาร์ทแอปพลิเคชัน ซึ่งรวมถึงฐานข้อมูล การจัดเก็บไฟล์ และระบบการตั้งค่า
Room เป็นชั้น ORM ที่ห่อหุ้ม SQLite ซึ่งช่วยลดการเขียน SQL queries และ ContentValues ด้วยตนเอง Room ตรวจสอบ SQL queries ในขั้นตอนการคอมไพล์ รองรับ Kotlin Coroutines และ Flow และสร้างโค้ดการเข้าถึงข้อมูลโดยอัตโนมัติ
SharedPreferences เหมาะสำหรับการจัดเก็บข้อมูลอย่างง่ายจำนวนเล็กน้อย: การตั้งค่าแอปพลิเคชัน แฟล็ก ตัวระบุ และความชอบของผู้ใช้ สำหรับข้อมูลที่ซับซ้อนหรือมีโครงสร้าง ควรใช้ Room หรือ DataStore
Core Data คือเฟรมเวิร์กของ Apple สำหรับจัดการกราฟของออบเจกต์ โดยรองรับการทำงานกับออบเจกต์ที่มีการจัดการ การติดตามการเปลี่ยนแปลง การโหลดแบบขี้เกียจ และการบันทึกอัตโนมัติลงในพื้นที่จัดเก็บถาวร (SQLite, XML หรือรูปแบบไบนารี)
การเลือกขึ้นอยู่กับความซับซ้อนของข้อมูล: สำหรับการตั้งค่าใช้ DataStore หรือ UserDefaults สำหรับข้อมูลที่มีโครงสร้างใช้ Room (Android) หรือ Core Data (iOS) สำหรับไฟล์ใช้ File Storage เกณฑ์ รวมถึงปริมาณข้อมูล ข้อกำหนดด้านประสิทธิภาพ และความจำเป็นในการเข้ารหัส การผสมผสานหลายกลไกในแอปพลิเคชันเดียวเป็นแนวปฏิบัติมาตรฐานที่ช่วยให้ใช้จุดแข็งของแต่ละวิธีได้อย่างเหมาะสมที่สุด
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม