DataStore: คืออะไร พื้นฐานการจัดเก็บข้อมูล และการแทนที่ SharedPreferences

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-03-12 เวลาอ่าน: 9 นาที

DataStore เป็นคอมโพเนนต์จากไลบรารี Jetpack ที่ออกแบบมาเพื่อจัดเก็บข้อมูลปริมาณน้อยในแอปพลิเคชัน Android ต่างจาก SharedPreferences ตรงที่มันทำงานแบบอะซิงโครนัสและรับประกันความสอดคล้องของข้อมูลภายใต้การเข้าถึงพร้อมกัน ตามข้อมูลของ Google, 2024 DataStore ใช้ Kotlin Coroutines และ Flow ซึ่งทำให้ปลอดภัยสำหรับเธรดหลักและเหมาะสำหรับสถาปัตยกรรมแบบรีแอกทีฟ

ประเด็นสำคัญ

  • DataStore — การแทนที่ SharedPreferences ด้วย API แบบอะซิงโครนัสและประเภทข้อมูลผ่าน Protocol Buffers
  • Preferences DataStore — ที่เก็บคีย์-ค่าแบบง่ายด้วยการอ่านผ่าน Flow และธุรกรรม
  • Proto DataStore — พื้นที่จัดเก็บแบบมีชนิดพร้อมการย้ายสคีมาอัตโนมัติ
  • SharedPreferences — API แบบซิงโครนัสที่บล็อกเธรด UI เมื่อมีปริมาณมาก
  • การย้ายข้อมูล ดำเนินการผ่านอินเทอร์เฟซ SharedPreferencesMigration โดยไม่สูญเสียข้อมูล

DataStore คืออะไร?

DataStore เป็นโซลูชันของ Google สำหรับการจัดเก็บข้อมูลในเครื่องบน Android ซึ่งเปิดตัวในปี 2020 เพื่อเป็นทางเลือกแทน SharedPreferences รองรับสองโหมด: Preferences DataStore (คู่คีย์-ค่าแบบง่าย) และ Proto DataStore (สคีมาแบบมีชนิดบนพื้นฐานของ Protocol Buffers)

ข้อได้เปรียบหลักคือการทำงานแบบอะซิงโครนัสอย่างสมบูรณ์: การอ่านทั้งหมดส่งคืน Flow จาก Kotlin Coroutines และการเขียนดำเนินการในบริบทของ coroutine ซึ่งช่วยขจัดการบล็อกเธรดหลักซึ่งเป็นปัญหาทั่วไปของ SharedPreferences เมื่อจัดการกับข้อมูลปริมาณมาก

DataStore รับประกันความเป็นอะตอมของการดำเนินการ: การเขียนพร้อมกันไม่ทำให้ข้อมูลสูญหายเนื่องจากโมเดลธุรกรรม หากคอมโพเนนต์สองตัวแก้ไขค่าเดียวกันพร้อมกัน DataStore จะจัดการข้อขัดแย้งอย่างถูกต้องผ่านกลไก compare-and-swap

ตามข้อมูลของ Google I/O 2023 DataStore ถูกใช้ใน 40% ของโปรเจกต์ Android ใหม่ และ Google แนะนำให้ย้ายจาก SharedPreferences ในแอปพลิเคชันทั้งหมดที่ต้องการความเสถียรของการจัดเก็บการตั้งค่า

สถาปัตยกรรมของ DataStore

หัวใจของ DataStore คือ SingleProcessDataStore — การทำงานภายในกระบวนการเดียว ใช้พื้นที่จัดเก็บแบบไฟล์พร้อมการล็อกระดับไฟล์: เมื่อเขียนข้อมูล ไฟล์จะถูกล็อกป้องกันการเสียหายภายใต้การเข้าถึงพร้อมกัน

DataStore จัดการข้อผิดพลาดการดีซีเรียลไลเซชันโดยอัตโนมัติ: หากไฟล์เสียหาย จะส่งคืนค่าเริ่มต้นและเขียนทับไฟล์ พฤติกรรมนี้สามารถกำหนดค่าได้ผ่าน corruptionHandler ซึ่งสามารถตั้งค่าได้เมื่อสร้าง DataStore

ปัญหาของ SharedPreferences ที่ DataStore แก้ไข

SharedPreferences มีปัญหาพื้นฐานสามประการ: การอ่านจากดิสก์แบบซิงโครนัสบนเธรดหลัก การขาดการรับประกันความเป็นอะตอมสำหรับการเขียนพร้อมกัน และไม่สามารถติดตามการเปลี่ยนแปลงแบบรีแอกทีฟ DataStore แก้ไขทั้งสาม: Flow สำหรับการสังเกต การล็อกไฟล์สำหรับความเป็นอะตอม และ API แบบอะซิงโครนัสสำหรับความปลอดภัยของเธรด

DataStore ทำงานอย่างไรใน Android?

DataStore จัดเก็บข้อมูลในไฟล์บนพื้นที่จัดเก็บภายในของอุปกรณ์ Preferences DataStore ใช้รูปแบบไฟล์คล้ายกับ SharedPreferences แต่มีเมตาดาต้าเพิ่มเติมสำหรับตรวจสอบความสมบูรณ์ Proto DataStore ใช้รูปแบบไบนารี Protocol Buffers ซึ่งลดขนาดไฟล์และเพิ่มความเร็วในการซีเรียลไลเซชัน

เมื่ออ่านข้อมูล DataStore จะโหลดไฟล์ทั้งหมดลงในหน่วยความจำครั้งเดียว จากนั้นสมาชิกจะได้รับสถานะปัจจุบันผ่าน Flow การเปลี่ยนแปลงจะถูกส่งไปยังสมาชิกที่ใช้งานอยู่ทั้งหมดโดยอัตโนมัติ — ไม่ต้องลงทะเบียน listener ด้วยตนเองเหมือน SharedPreferences

Preferences DataStore ทำงานอย่างไร

Preferences DataStore ใช้กลไกการซีเรียลไลเซชันในตัวบนพื้นฐานของ Map แต่ละรายการคือคู่ของสตริงและชนิดพื้นฐาน (Int, Boolean, Float, Long, String, Set) ข้อมูลถูกเก็บในไฟล์ XML คล้าย SharedPreferences แต่เขียนแบบอะตอมผ่านการล็อกไฟล์

ตัวอย่างการสร้าง Preferences DataStore: ส่วนขยาย preferencesDataStore บน Context สร้างซิงเกิลตันด้วยชื่อไฟล์ เมื่อเรียกซ้ำ จะส่งคืนอินสแตนซ์เดียวกัน — ซึ่งช่วยลดการซ้ำซ้อนของไฟล์และความสับสนระหว่างอินสแตนซ์พื้นที่จัดเก็บต่างๆ

Proto DataStore ทำงานอย่างไร

Proto DataStore ต้องการการกำหนดสคีมาข้อมูลผ่านไฟล์ .proto และคอมไพล์ด้วยปลั๊กอิน protobuf คลาส Java ที่สร้างขึ้นจะถูกใช้เป็นจุดเข้าเดียวสำหรับทุกฟิลด์ — ซึ่งช่วยขจัดการพิมพ์ผิดในคีย์ซึ่งพบได้บ่อยใน SharedPreferences

สคีมาของ Proto DataStore ถูกกำหนดครั้งเดียวและรองรับการเพิ่มฟิลด์ใหม่โดยไม่สูญเสียข้อมูลเก่า หากแอปเวอร์ชันใหม่เพิ่มฟิลด์ที่มีค่าเริ่มต้น ไฟล์เก่าจะถูกดีซีเรียลไลซ์อย่างถูกต้อง — ความเข้ากันได้ย้อนหลัง ถูกสร้างไว้ในโปรโตคอล

Preferences DataStore และ Proto DataStore: การเปรียบเทียบ

การเลือกระหว่าง Preferences DataStore และ Proto DataStore ขึ้นอยู่กับความซับซ้อนของข้อมูลและข้อกำหนดด้านชนิด ทั้งสองตัวเลือกเป็นแบบอะซิงโครนัสและธุรกรรม แต่แตกต่างกันในความปลอดภัยของชนิดและประสิทธิภาพการซีเรียลไลเซชัน

คุณลักษณะPreferences DataStoreProto DataStore
การกำหนดชนิดอ่อน (คีย์-ค่า)เข้มแข็ง (คลาสที่สร้างขึ้น)
การซีเรียลไลเซชันXML (ในตัว)Protocol Buffers (protobuf)
ขนาดไฟล์ใหญ่ (XML ที่อ่านได้)เล็ก (ไบนารี)
ความซับซ้อนต่ำ (ไม่ต้องใช้ .proto)ปานกลาง (ต้องใช้ .proto)
การย้ายสคีมาไม่มีสคีมาอัตโนมัติ (proto)
ความเข้ากันได้SharedPreferences (ผ่านการย้าย)เฉพาะ Proto DataStore

เมื่อใดควรเลือก Preferences DataStore

Preferences DataStore เหมาะสำหรับการตั้งค่าอย่างง่าย: แฟล็กคุณสมบัติ สตริงโทเคนการอนุญาต จำนวนครั้งที่เปิดแอป หากข้อมูลมีน้อย (มากถึง 10–15 คีย์) และไม่ต้องการสคีมาที่เข้มงวด Preferences DataStore ให้เกณฑ์การเข้าขั้นต่ำโดยไม่ต้องเชื่อมต่อปลั๊กอิน protobuf

เมื่อใดควรเลือก Proto DataStore

Proto DataStore เหมาะสมเมื่อโครงสร้างข้อมูลซับซ้อนหรืออาจเปลี่ยนแปลงระหว่างเวอร์ชันของแอป ตัวอย่างเช่น การตั้งค่าโปรไฟล์ผู้ใช้หรือการกำหนดค่าทดสอบ A/B ที่มี 20+ ฟิลด์ Protobuf ให้การกำหนดชนิดที่เข้มแข็งและการย้ายข้อมูลอัตโนมัติ ช่วยขจัดข้อผิดพลาดรันไทม์เนื่องจากคีย์ไม่ตรงกัน

วิธีย้ายจาก SharedPreferences ไปยัง DataStore

Google มีกลไกการย้ายข้อมูลในตัวผ่านคลาส SharedPreferencesMigration การย้ายจะดำเนินการครั้งเดียวเมื่อเปิดครั้งแรกหลังจากอัปเดตแอป: DataStore อ่านข้อมูลจาก SharedPreferences เขียนในรูปแบบของตัวเอง และทำเครื่องหมายว่าการย้ายเสร็จสมบูรณ์

การย้ายรองรับการแปลงแบบกำหนดเอง: หากคีย์ใน SharedPreferences ไม่ตรงกับคีย์ DataStore ที่ต้องการ คุณสามารถระบุฟังก์ชันการแปลงผ่าน SharedPreferencesMigration ซึ่งช่วยให้เปลี่ยนชื่อคีย์และเปลี่ยนชนิดข้อมูลระหว่างการย้ายได้

การย้ายทีละขั้นตอน

ขั้นแรก เพิ่ม DataStore ใน build.gradle และสร้างอินสแตนซ์ DataStore พร้อมการย้าย: SharedPreferencesMigration รับชื่อไฟล์ SharedPreferences และชุดของคีย์ที่จะย้าย ขั้นที่สอง ลบโค้ดทั้งหมดที่ทำงานผ่าน SharedPreferences และแทนที่ด้วยการเรียก DataStore ขั้นที่สาม ทดสอบการย้าย: เมื่อเปิดครั้งแรก ข้อมูลควรปรากฏใน DataStore และไฟล์ SharedPreferences เก่าควรจะไม่ถูกใช้อีกต่อไป

kotlin
val Context.dataStore by preferencesDataStore(
    name = "settings",
    produceMigrations = { context ->
        listOf(
            SharedPreferencesMigration(context, "old_prefs")
        )
    }
)

ตัวอย่างการใช้ DataStore ในโค้ด

DataStore ผสานรวมเข้ากับโปรเจกต์ที่มีอยู่ได้อย่างง่ายดาย ด้านล่างเป็นตัวอย่างเชิงปฏิบัติสำหรับ Preferences DataStore และ Proto DataStore — ทั้งสองสาธิตการอ่าน การเขียน และการสังเกตการเปลี่ยนแปลงแบบรีแอกทีฟ

Preferences DataStore: การอ่านและเขียนการตั้งค่า

ในตัวอย่างนี้ Preferences DataStore จัดเก็บสามการตั้งค่า: ธีมมืด ชื่อผู้ใช้ และจำนวนครั้งที่เปิด การอ่านทำผ่านส่วนขยาย .data ซึ่งส่งคืน Flow การเขียนทำผ่านฟังก์ชันระงับ .edit ซึ่งรับประกันความเป็นอะตอมของการเปลี่ยนแปลง

kotlin
val Context.settingsDataStore by preferencesDataStore(name = "settings")

val isDarkMode: Flow<Boolean> = settingsDataStore.data
    .map { preferences ->
        preferences[booleanPreferencesKey("dark_mode")] ?: false
    }

suspend fun toggleDarkMode() {
    settingsDataStore.edit { prefs ->
        val current = prefs[booleanPreferencesKey("dark_mode")] ?: false
        prefs[booleanPreferencesKey("dark_mode")] = !current
    }
}

Proto DataStore: สคีมาและการใช้งาน

Proto DataStore ต้องการการกำหนดไฟล์ .proto หลังจากคอมไพล์ จะสร้างคลาส UserSettings ที่ใช้สำหรับอ่านและเขียน การย้ายเวอร์ชันของสคีมาอธิบายไว้ในไฟล์ .proto เดียวกันและถูกนำไปใช้โดยอัตโนมัติ

kotlin
// user_preferences.proto
syntax = "proto3";

message UserPreferences {
    string display_name = 1;
    int32 notification_count = 2;
    bool notifications_enabled = 3;
}

// การอ่านจาก DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// การเขียนค่าใหม่
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

การสังเกตการเปลี่ยนแปลงแบบรีแอกทีฟ

DataStore ผสานรวมกับสถาปัตยกรรม MVVM ผ่าน ViewModel Flow จาก DataStore ถูกรวบรวมผ่าน .stateIn และใช้ใน UI ทุกครั้งที่ข้อมูลเปลี่ยนแปลง UI จะอัปเดตโดยอัตโนมัติ — ไม่ต้องอัปเดตด้วยตนเองหรือ LiveData

kotlin
class SettingsViewModel(
    private val dataStore: DataStore<Preferences>
) : ViewModel() {

    val uiState: StateFlow<SettingsUiState> =
        dataStore.data
            .map { prefs ->
                SettingsUiState(
                    isDarkMode = prefs[booleanPreferencesKey("dark_mode")] ?: false,
                    counter = prefs[intPreferencesKey("launch_count")] ?: 0
                )
            }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5000),
                initialValue = SettingsUiState()
            )
}

คำถามที่พบบ่อย

DataStore ดีกว่า SharedPreferences อย่างไร?

DataStore ทำงานแบบอะซิงโครนัส (ไม่บล็อกเธรด UI) รองรับการเข้าถึงพร้อมกันผ่านธุรกรรม และอนุญาตให้สมัครรับการเปลี่ยนแปลงแบบรีแอกทีฟผ่าน Flow SharedPreferences เป็น API แบบซิงโครนัสที่มีความเสี่ยง ANR เมื่อมีข้อมูลปริมาณมากและไม่มีการสนับสนุนรีแอกทีฟในตัว

สามารถใช้ DataStore กับ Java ได้หรือไม่?

DataStore เขียนด้วย Kotlin และต้องใช้ Kotlin Coroutines การใช้จาก Java เป็นไปได้แต่ไม่สะดวก: คุณจะต้องสร้าง wrapper ด้วย CompletableFuture หรือจัดการ coroutine ด้วยตนเอง สำหรับโปรเจกต์ Java Google แนะนำให้ใช้ SharedPreferences ต่อไปหรือเพิ่ม Kotlin ในโมดูล

DataStore เหมาะสำหรับจัดเก็บข้อมูลปริมาณมากหรือไม่?

DataStore โหลดไฟล์ทั้งหมดในหน่วยความจำเมื่ออ่าน ดังนั้นจึงไม่เหมาะสำหรับจัดเก็บรายการหรือวัตถุขนาดใหญ่ สำหรับสถานการณ์ดังกล่าว ให้ใช้ Room หรือ SQLite DataStore ถูกปรับให้เหมาะสมสำหรับการตั้งค่าและข้อมูลที่มีโครงสร้างขนาดเล็ก — สูงสุดหลายร้อยกิโลไบต์

วิธีจัดการกับข้อผิดพลาดไฟล์ DataStore ที่เสียหาย?

เมื่อสร้าง DataStore คุณสามารถส่ง corruptionHandler — ฟังก์ชันที่ถูกเรียกเมื่อไฟล์เสียหาย โดยค่าเริ่มต้น DataStore จะโยน CorruptionException ใน corruptionHandler คุณสามารถส่งคืนข้อมูลว่าง จากนั้น DataStore จะเขียนทับไฟล์ด้วยสถานะที่ถูกต้อง

Proto DataStore ต้องใช้ไฟล์ .proto หรือไม่?

ใช่ Proto DataStore ต้องการการกำหนดสคีมาในไฟล์ .proto และเชื่อมต่อปลั๊กอิน protobuf-gradle-plugin หากโปรเจกต์เล็กและข้อมูลเรียบง่าย การใช้ Preferences DataStore จะง่ายกว่า — ไม่ต้องกำหนดค่าการ build เพิ่มเติม

สรุป

  • DataStore — การแทนที่ SharedPreferences สมัยใหม่ที่ทำงานกับ Kotlin Coroutines และ Flow
  • Preferences DataStore — คีย์-ค่าแบบง่ายไม่มีสคีมา เหมาะสำหรับการตั้งค่า
  • Proto DataStore — พื้นที่จัดเก็บแบบมีชนิดพร้อมสคีมา protobuf และการย้ายอัตโนมัติ
  • การย้าย จาก SharedPreferences ถูกสร้างไว้ใน DataStore ผ่าน SharedPreferencesMigration
  • ความปลอดภัยของเธรด — การดำเนินการทั้งหมดเป็นแบบอะซิงโครนัส ไม่มีการบล็อก UI
  • รีแอกทีฟ — Flow แจ้งสมาชิกทุกครั้งที่มีการเปลี่ยนแปลงข้อมูล
  • คำแนะนำ — ใช้ DataStore ในโปรเจกต์ Android ใหม่ทั้งหมด ย้ายโปรเจกต์ที่มีอยู่เมื่อทำงานกับการตั้งค่า

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม