DataStore ซึ่งเป็นส่วนหนึ่งของ Android Jetpack.
Jetpack DataStore เป็นโซลูชันพื้นที่เก็บข้อมูลที่ช่วยให้คุณจัดเก็บคู่คีย์-ค่า หรือออบเจ็กต์ที่มีการพิมพ์ด้วย บัฟเฟอร์โปรโตคอลได้ DataStore ใช้โครูทีนและ Flow ของ Kotlin เพื่อจัดเก็บข้อมูลแบบไม่พร้อมกัน อย่างสม่ำเสมอ และเป็นธุรกรรม
หากใช้ SharedPreferences เพื่อจัดเก็บข้อมูล ให้ลองย้ายข้อมูลไปยัง
DataStore แทน
DataStore API
อินเทอร์เฟซ DataStore มี API ดังนี้
Flow ที่ใช้เพื่ออ่านข้อมูลจาก DataStore ได้
val data: Flow<T>ฟังก์ชันสำหรับอัปเดตข้อมูลใน DataStore
suspend updateData(transform: suspend (t) -> T)
การกำหนดค่า DataStore
หากต้องการจัดเก็บและเข้าถึงข้อมูลโดยใช้คีย์ ให้ใช้การใช้งาน Preferences DataStore ซึ่งไม่จำเป็นต้องมีสคีมาที่กำหนดไว้ล่วงหน้า และไม่มีความปลอดภัยในการกำหนดประเภท โดยมี API ที่คล้ายกับ SharedPreferences แต่ไม่มี
ข้อเสียที่เกี่ยวข้องกับค่ากำหนดที่แชร์
DataStore ช่วยให้คุณเก็บคลาสที่กำหนดเองไว้ได้ หากต้องการทำเช่นนี้ คุณต้องกำหนดสคีมาสำหรับข้อมูลและระบุ Serializer เพื่อแปลงข้อมูลให้อยู่ในรูปแบบที่เก็บไว้ได้ คุณสามารถเลือกใช้บัฟเฟอร์โปรโตคอล, JSON หรือกลยุทธ์การซีเรียลไลซ์อื่นๆ
ตั้งค่า
หากต้องการใช้ Jetpack DataStore ในแอป ให้เพิ่มข้อมูลต่อไปนี้ลงในไฟล์ Gradle โดยขึ้นอยู่กับการใช้งานที่คุณต้องการใช้
Preferences DataStore
เพิ่มบรรทัดต่อไปนี้ลงในส่วนทรัพยากร Dependency ของไฟล์ Gradle
Groovy
dependencies { // Preferences DataStore (SharedPreferences like APIs) implementation "androidx.datastore:datastore-preferences:1.2.1" // Alternatively - without an Android dependency. implementation "androidx.datastore:datastore-preferences-core:1.2.1" }
Kotlin
dependencies { // Preferences DataStore (SharedPreferences like APIs) implementation("androidx.datastore:datastore-preferences:1.2.1") // Alternatively - without an Android dependency. implementation("androidx.datastore:datastore-preferences-core:1.2.1") }
หากต้องการเพิ่มการรองรับ RxJava (ไม่บังคับ) ให้เพิ่มทรัพยากร Dependency ต่อไปนี้
Groovy
dependencies { // optional - RxJava2 support implementation "androidx.datastore:datastore-preferences-rxjava2:1.2.1" // optional - RxJava3 support implementation "androidx.datastore:datastore-preferences-rxjava3:1.2.1" }
Kotlin
dependencies { // optional - RxJava2 support implementation("androidx.datastore:datastore-preferences-rxjava2:1.2.1") // optional - RxJava3 support implementation("androidx.datastore:datastore-preferences-rxjava3:1.2.1") }
DataStore
เพิ่มบรรทัดต่อไปนี้ลงในส่วนทรัพยากร Dependency ของไฟล์ Gradle
Groovy
dependencies { // Typed DataStore for custom data objects (for example, using Proto or JSON). implementation "androidx.datastore:datastore:1.2.1" // Alternatively - without an Android dependency. implementation "androidx.datastore:datastore-core:1.2.1" }
Kotlin
dependencies { // Typed DataStore for custom data objects (for example, using Proto or JSON). implementation("androidx.datastore:datastore:1.2.1") // Alternatively - without an Android dependency. implementation("androidx.datastore:datastore-core:1.2.1") }
เพิ่มทรัพยากร Dependency ที่ไม่บังคับต่อไปนี้สำหรับการรองรับ RxJava
Groovy
dependencies { // optional - RxJava2 support implementation "androidx.datastore:datastore-rxjava2:1.2.1" // optional - RxJava3 support implementation "androidx.datastore:datastore-rxjava3:1.2.1" }
Kotlin
dependencies { // optional - RxJava2 support implementation("androidx.datastore:datastore-rxjava2:1.2.1") // optional - RxJava3 support implementation("androidx.datastore:datastore-rxjava3:1.2.1") }
หากต้องการทำให้เนื้อหาเป็นแบบอนุกรม ให้เพิ่มการอ้างอิงสำหรับการทำให้เป็นอนุกรมของ Protocol Buffers หรือ JSON
การซีเรียลไลซ์ JSON
หากต้องการใช้การซีเรียลไลซ์ JSON ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ Gradle
Groovy
plugins { id("org.jetbrains.kotlin.plugin.serialization") version "2.2.20" } dependencies { implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0" }
Kotlin
plugins { id("org.jetbrains.kotlin.plugin.serialization") version "2.2.20" } dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") }
การทำให้เป็นอนุกรม Protobuf
หากต้องการใช้การซีเรียลไลซ์ Protobuf ให้เพิ่มข้อมูลต่อไปนี้ลงในไฟล์ Gradle
Groovy
plugins { id("com.google.protobuf") version "0.9.5" } dependencies { implementation "com.google.protobuf:protobuf-kotlin-lite:4.32.1" } protobuf { protoc { artifact = "com.google.protobuf:protoc:4.32.1" } generateProtoTasks { all().forEach { task -> task.builtins { create("java") { option("lite") } create("kotlin") } } } }
Kotlin
plugins { id("com.google.protobuf") version "0.9.5" } dependencies { implementation("com.google.protobuf:protobuf-kotlin-lite:4.32.1") } protobuf { protoc { artifact = "com.google.protobuf:protoc:4.32.1" } generateProtoTasks { all().forEach { task -> task.builtins { create("java") { option("lite") } create("kotlin") } } } }
ใช้ DataStore อย่างถูกต้อง
หากต้องการใช้ DataStore อย่างถูกต้อง ให้คำนึงถึงกฎต่อไปนี้เสมอ
อย่าสร้างอินสแตนซ์ของ
DataStoreมากกว่า 1 รายการสำหรับไฟล์ที่กำหนดใน กระบวนการเดียวกัน การทำเช่นนี้อาจทำให้ฟังก์ชันการทำงานทั้งหมดของ DataStore หยุดทำงาน หากมี DataStore หลายรายการที่ใช้งานอยู่สำหรับไฟล์ที่กำหนดในกระบวนการเดียวกัน DataStore จะแสดงIllegalStateExceptionเมื่ออ่านหรืออัปเดตข้อมูลประเภททั่วไปของ
DataStore<T>ต้องเปลี่ยนแปลงไม่ได้ การเปลี่ยนแปลงประเภทที่ใช้ใน DataStore จะทำให้ความสอดคล้องที่ DataStore มีให้ไม่ถูกต้อง และอาจทำให้เกิดข้อบกพร่องที่ร้ายแรงและตรวจพบได้ยาก เราขอแนะนำให้คุณใช้บัฟเฟอร์โปรโตคอล ซึ่งช่วยให้มั่นใจได้ว่าข้อมูลจะเปลี่ยนแปลงไม่ได้ มี API ที่ชัดเจน และการซีเรียลไลซ์มีประสิทธิภาพอย่าใช้
SingleProcessDataStoreและMultiProcessDataStoreร่วมกันสำหรับไฟล์เดียวกัน หากต้องการเข้าถึงDataStoreจากกระบวนการมากกว่า 1 รายการ คุณต้องใช้MultiProcessDataStore
คำจำกัดความของข้อมูล
Preferences DataStore
กำหนดคีย์ที่จะใช้เพื่อเก็บข้อมูลไว้ในดิสก์
val EXAMPLE_COUNTER = intPreferencesKey("example_counter")
JSON DataStore
สำหรับ JSON DataStore ให้เพิ่มคำอธิบายประกอบ @Serialization ลงในข้อมูลที่ต้องการเก็บไว้
@Serializable data class Settings(val exampleCounter: Int)
กำหนดคลาสที่ใช้ Serializer<T> โดยที่ T คือประเภทของ
คลาสที่คุณเพิ่มคำอธิบายประกอบก่อนหน้านี้ ตรวจสอบว่าคุณได้ใส่ค่าเริ่มต้นสำหรับ Serializer ที่จะใช้หากยังไม่มีการสร้างไฟล์
object SettingsSerializer : Serializer<Settings> { override val defaultValue: Settings = Settings(exampleCounter = 0) override suspend fun readFrom(input: InputStream): Settings = try { Json.decodeFromString(Settings.serializer(), input.readBytes().decodeToString()) } catch (serialization: SerializationException) { throw CorruptionException("Unable to read Settings", serialization) } override suspend fun writeTo(t: Settings, output: OutputStream) { output.write(Json.encodeToString(Settings.serializer(), t).encodeToByteArray()) } }
Proto DataStore
การใช้งาน Proto DataStore ใช้ DataStore และ บัฟเฟอร์โปรโตคอล เพื่อ เก็บออบเจ็กต์ที่มีการพิมพ์ไว้ในดิสก์
Proto DataStore ต้องมีสคีมาที่กำหนดไว้ล่วงหน้าในไฟล์โปรโตในไดเรกทอรี app/src/main/proto/ สคีมานี้กำหนดประเภทสำหรับออบเจ็กต์ที่คุณเก็บไว้ใน Proto DataStore ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดสคีมาโปรโต
ได้ที่คู่มือภาษา protobuf
เพิ่มไฟล์ชื่อ settings.proto ลงในโฟลเดอร์ src/main/proto
syntax = "proto3"; option java_package = "com.example.datastoresampleapp"; option java_multiple_files = true; message Settings { int32 counter = 1; bool foo = 2; }
กำหนดคลาสที่ใช้ Serializer<T> โดยที่ T คือประเภทที่กำหนดไว้
ในไฟล์โปรโต คลาส Serializer นี้กำหนดวิธีที่ DataStore อ่านและเขียนประเภทข้อมูล ตรวจสอบว่าคุณได้ใส่ค่าเริ่มต้นสำหรับ Serializer ที่จะใช้หากยังไม่มีการสร้างไฟล์
object SettingsSerializer : Serializer<Settings> { override val defaultValue: Settings = Settings.getDefaultInstance() override suspend fun readFrom(input: InputStream): Settings { try { return Settings.parseFrom(input) } catch (exception: InvalidProtocolBufferException) { throw CorruptionException("Cannot read proto.", exception) } } override suspend fun writeTo(t: Settings, output: OutputStream) { return t.writeTo(output) } }
สร้าง DataStore
คุณต้องระบุชื่อสำหรับไฟล์ที่จะใช้เพื่อเก็บข้อมูลไว้
Preferences DataStore
การใช้งาน Preferences DataStore ใช้คลาส DataStore และ
Preferences เพื่อเก็บคู่คีย์-ค่าไว้ในดิสก์ ใช้
ผู้รับมอบสิทธิ์พร็อพเพอร์ตี้ที่สร้างโดย preferencesDataStore เพื่อสร้างอินสแตนซ์
ของ DataStore<Preferences> เรียกใช้เพียงครั้งเดียวที่ระดับบนสุดของไฟล์ Kotlin เข้าถึง DataStore ผ่านพร็อพเพอร์ตี้นี้ตลอดทั้งแอปพลิเคชัน ซึ่งจะช่วยให้ DataStore เป็นซิงเกิลตันได้ง่ายขึ้น
พารามิเตอร์ name ที่บังคับคือชื่อของ Preferences DataStore
// At the top level of your kotlin file: val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
JSON DataStore
ใช้ผู้รับมอบสิทธิ์พร็อพเพอร์ตี้ที่สร้างโดย dataStore เพื่อสร้างอินสแตนซ์ของ
DataStore<T> โดยที่ T คือคลาสข้อมูลที่ซีเรียลไลซ์ได้ เรียกใช้เพียงครั้งเดียวที่ระดับบนสุดของไฟล์ Kotlin และเข้าถึงผ่านผู้รับมอบสิทธิ์พร็อพเพอร์ตี้นี้ตลอดทั้งแอป พารามิเตอร์ fileName จะบอก DataStore ว่าจะใช้ไฟล์ใดในการจัดเก็บข้อมูล และพารามิเตอร์ serializer จะบอก DataStore ถึงชื่อของคลาส Serializer ที่กำหนดไว้ก่อนหน้านี้
val Context.dataStore: DataStore<Settings> by dataStore( fileName = "settings.json", serializer = SettingsSerializer, scope = CoroutineScope(Dispatchers.IO + SupervisorJob()), )
Proto DataStore
ใช้ผู้รับมอบสิทธิ์พร็อพเพอร์ตี้ที่สร้างโดย dataStore เพื่อสร้างอินสแตนซ์ของ
DataStore<T> โดยที่ T คือประเภทที่กำหนดไว้ในไฟล์โปรโต เรียกใช้เพียงครั้งเดียวที่ระดับบนสุดของไฟล์ Kotlin และเข้าถึงผ่านผู้รับมอบสิทธิ์พร็อพเพอร์ตี้นี้ตลอดทั้งแอป พารามิเตอร์ fileName จะบอก DataStore ว่าจะใช้ไฟล์ใดในการจัดเก็บข้อมูล และพารามิเตอร์ serializer จะบอก DataStore ถึงชื่อของคลาส Serializer ที่กำหนดไว้ก่อนหน้านี้
val Context.dataStore: DataStore<Settings> by dataStore(fileName = "settings.pb", serializer = SettingsSerializer)
อ่านจาก DataStore
คุณต้องระบุชื่อสำหรับไฟล์ที่จะใช้เพื่อเก็บข้อมูลไว้
Preferences DataStore
เนื่องจาก Preferences DataStore ไม่ได้ใช้สคีมาที่กำหนดไว้ล่วงหน้า คุณจึงต้องใช้
ฟังก์ชันประเภทคีย์ที่เกี่ยวข้องเพื่อกำหนดคีย์สำหรับแต่ละค่าที่คุณ
ต้องการจัดเก็บในอินสแตนซ์ DataStore<Preferences> ตัวอย่างเช่น หากต้องการกำหนด
คีย์สำหรับค่า int ให้ใช้ intPreferencesKey จากนั้นใช้พร็อพเพอร์ตี้
DataStore.data เพื่อแสดงค่าที่จัดเก็บไว้ที่เหมาะสมโดยใช้
Flow
fun counterFlow(): Flow<Int> = context.dataStore.data.map { preferences -> preferences[EXAMPLE_COUNTER] ?: 0 }
JSON DataStore
ใช้ DataStore.data เพื่อแสดง Flow ของพร็อพเพอร์ตี้ที่เหมาะสมจากออบเจ็กต์ที่จัดเก็บไว้
fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings -> settings.exampleCounter }
Proto DataStore
ใช้ DataStore.data เพื่อแสดง Flow ของพร็อพเพอร์ตี้ที่เหมาะสมจากออบเจ็กต์ที่จัดเก็บไว้
fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings -> settings.counter }
ใช้ collectAsStateWithLifecycle เพื่อใช้ Flow ที่สร้างโดย
ViewModel ใน Composable
ซึ่งจะแปลง DataStore Flow เป็น Compose State ที่ทริกเกอร์การจัดองค์ประกอบใหม่ได้อย่างปลอดภัย
@Composable
fun SomeScreen(counterFlow: Flow<Int>) {
val counter by counterFlow.collectAsStateWithLifecycle(initialValue = 0)
Text(text = "Example counter: ${counter}")
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับ collectAsStateWithLifecycle,
ได้ที่ State และ Jetpack Compose
เขียนลงใน DataStore
DataStore มีฟังก์ชัน updateData ที่อัปเดตออบเจ็กต์ที่
จัดเก็บไว้แบบเป็นธุรกรรม updateData จะแสดงสถานะปัจจุบันของข้อมูลเป็นอินสแตนซ์ของประเภทข้อมูล และอัปเดตข้อมูลแบบเป็นธุรกรรมในการดำเนินการอ่าน-เขียน-แก้ไขแบบอะตอมมิก ระบบจะถือว่าโค้ดทั้งหมดในบล็อก updateData เป็นธุรกรรมเดียว
Preferences DataStore
suspend fun incrementCounter() { context.dataStore.updateData { it.toMutablePreferences().also { preferences -> preferences[EXAMPLE_COUNTER] = (preferences[EXAMPLE_COUNTER] ?: 0) + 1 } } }
JSON DataStore
suspend fun incrementCounter() { context.dataStore.updateData { settings -> settings.copy(exampleCounter = settings.exampleCounter + 1) } }
Proto DataStore
suspend fun incrementCounter() { context.dataStore.updateData { settings -> settings.toBuilder().setCounter(settings.counter + 1).build() } }
ใช้ DataStore ในแอป Compose
หากต้องการใช้ DataStore ในแอป Compose ให้ทำตามหลักเกณฑ์สถาปัตยกรรมของแอป Android โดยเก็บการดำเนินการ DataStore ไว้ในชั้นข้อมูล (เช่น ที่เก็บ) และแสดงข้อมูลไปยัง UI ผ่าน ViewModel
หลีกเลี่ยงการอ่านหรือเขียนลงใน DataStore โดยตรงภายในฟังก์ชัน Composable
แสดง DataStore ผ่าน ViewModel ส่งที่เก็บ (ซึ่งรวม DataStore ไว้) ไปยัง
ViewModelและ แปลงFlowเป็นStateFlowเพื่อให้ UI สังเกตได้ ดังที่แสดงใน ข้อมูลโค้ดต่อไปนี้class SettingsViewModel( private val userPreferencesRepository: UserPreferencesRepository ) : ViewModel() { // Expose the DataStore flow as a StateFlow for Compose val userSettings: StateFlow<UserSettings> = userPreferencesRepository.userSettingsFlow .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = UserSettings.getDefaultInstance() ) fun updateCounter(newValue: Int) { viewModelScope.launch { userPreferencesRepository.updateCounter(newValue) } } }สังเกตและเขียนจาก Composable ใช้
collectAsStateWithLifecycleเพื่อสังเกตStateFlowใน UI อย่างปลอดภัย และเรียกใช้ฟังก์ชันViewModelเพื่อจัดการการเขียน ดังที่แสดงในข้อมูลโค้ดต่อไปนี้@Composable fun SettingsScreen( viewModel: SettingsViewModel = viewModel() ) { // Safely collect the state val settings by viewModel.userSettings.collectAsStateWithLifecycle() Column(modifier = Modifier.padding(16.dp)) { Text(text = "Current counter: ${settings.counter}") Spacer(modifier = Modifier.height(8.dp)) Button(onClick = { viewModel.updateCounter(settings.counter + 1) }) { Text("Increment Counter") } } }
ใช้ DataStore ในโค้ดแบบหลายกระบวนการ
คุณสามารถกำหนดค่า DataStore เพื่อเข้าถึงข้อมูลเดียวกันในกระบวนการต่างๆ ด้วยพร็อพเพอร์ตี้ความสอดคล้องของข้อมูลเดียวกันกับที่อยู่ในกระบวนการเดียว โดยเฉพาะอย่างยิ่ง DataStore มีพร็อพเพอร์ตี้ต่อไปนี้
- การอ่านจะแสดงเฉพาะข้อมูลที่เก็บไว้ในดิสก์เท่านั้น
- ความสอดคล้องแบบอ่านหลังเขียน
- การเขียนจะถูกซีเรียลไลซ์
- การเขียนจะไม่บล็อกการอ่าน
ลองดูแอปพลิเคชันตัวอย่างที่มีบริการและกิจกรรม โดยบริการทำงานในกระบวนการแยกต่างหากและอัปเดต DataStore เป็นระยะ
ตัวอย่างนี้ใช้ JSON DataStore แต่คุณยังใช้ Preferences หรือ Proto DataStore ได้ด้วย
@Serializable data class Time(val lastUpdateMillis: Long)
Serializer จะบอก DataStore ถึงวิธีอ่านและเขียนประเภทข้อมูล ตรวจสอบว่าคุณได้ใส่ค่าเริ่มต้นสำหรับ Serializer ที่จะใช้หากยังไม่มีการสร้างไฟล์ ตัวอย่างการใช้งานโดยใช้
kotlinx.serialization มีดังนี้
object TimeSerializer : Serializer<Time> { override val defaultValue: Time = Time(lastUpdateMillis = 0L) override suspend fun readFrom(input: InputStream): Time = try { Json.decodeFromString(Time.serializer(), input.readBytes().decodeToString()) } catch (serialization: SerializationException) { throw CorruptionException("Unable to read Time", serialization) } override suspend fun writeTo(t: Time, output: OutputStream) { output.write(Json.encodeToString(Time.serializer(), t).encodeToByteArray()) } }
หากต้องการใช้ DataStore ในกระบวนการต่างๆ คุณต้องสร้าง
ออบเจ็กต์ DataStore โดยใช้ MultiProcessDataStoreFactory สำหรับทั้งโค้ดแอป
และโค้ดบริการ
val dataStore = MultiProcessDataStoreFactory.create( serializer = TimeSerializer, produceFile = { context.dataStoreFile("time.pb") }, corruptionHandler = null, )
เพิ่มข้อมูลต่อไปนี้ลงใน AndroidManifiest.xml
<service android:name="com.example.datastore.snippets.TimestampUpdateService" android:exported="false" android:process=":service" />
บริการจะเรียกใช้ updateLastUpdateTime เป็นระยะ ซึ่งจะเขียนลงใน DataStore โดยใช้ updateData
suspend fun updateLastUpdateTime() { dataStore.updateData { time -> time.copy(lastUpdateMillis = System.currentTimeMillis()) } }
แอปจะอ่านค่าที่บริการเขียนโดยใช้โฟลว์ข้อมูลดังนี้
fun timeFlow(): Flow<Long> = dataStore.data.map { time -> time.lastUpdateMillis }
ตอนนี้เราสามารถรวมฟังก์ชันทั้งหมดนี้ไว้ในคลาสที่ชื่อ MultiProcessDataStore และใช้ในแอปได้แล้ว
โค้ดบริการมีดังนี้
class TimestampUpdateService : Service() { val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) val multiProcessDataStore by lazy { MultiProcessDataStore(applicationContext) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { serviceScope.launch { while (true) { multiProcessDataStore.updateLastUpdateTime() delay(1000) } } return START_NOT_STICKY } override fun onDestroy() { super.onDestroy() serviceScope.cancel() } }
และโค้ดแอปมีดังนี้
val context = LocalContext.current val coroutineScope = rememberCoroutineScope() val multiProcessDataStore = remember(context) { MultiProcessDataStore(context) } // Display time written by other process. val lastUpdateTime by multiProcessDataStore .timeFlow() .collectAsState(initial = 0, coroutineScope.coroutineContext) Text(text = "Last updated: $lastUpdateTime", fontSize = 25.sp) DisposableEffect(context) { val serviceIntent = Intent(context, TimestampUpdateService::class.java) context.startService(serviceIntent) onDispose { context.stopService(serviceIntent) } }
คุณสามารถใช้ Hilt การแทรกทรัพยากร Dependency เพื่อให้อินสแตนซ์ DataStore ไม่ซ้ำกันในแต่ละกระบวนการ
@Provides
@Singleton
fun provideDataStore(@ApplicationContext context: Context): DataStore<Settings> =
MultiProcessDataStoreFactory.create(...)
จัดการไฟล์เสียหาย
ในบางกรณีที่เกิดขึ้นไม่บ่อยนัก ไฟล์ที่เก็บไว้ในดิสก์ของ DataStore อาจเสียหาย โดยค่าเริ่มต้น DataStore จะไม่กู้คืนจากความเสียหายโดยอัตโนมัติ และการพยายามอ่านจากไฟล์ที่เสียหายจะทำให้ระบบแสดง CorruptionException
DataStore มี Corruption Handler API ที่ช่วยให้คุณกู้คืนได้อย่างราบรื่นในสถานการณ์ดังกล่าว และหลีกเลี่ยงการแสดงข้อยกเว้น เมื่อกำหนดค่าแล้ว Corruption Handler จะแทนที่ไฟล์ที่เสียหายด้วยไฟล์ใหม่ที่มีค่าเริ่มต้นที่กำหนดไว้ล่วงหน้า
หากต้องการตั้งค่า Handler นี้ ให้ระบุ corruptionHandler เมื่อสร้างอินสแตนซ์ DataStore ใน by dataStore หรือในเมธอด Factory ของ DataStoreFactory
val dataStore: DataStore<Settings> = DataStoreFactory.create(
serializer = SettingsSerializer(),
produceFile = {
File("${context.filesDir.path}/myapp.preferences_pb")
},
corruptionHandler = ReplaceFileCorruptionHandler { Settings(lastUpdate = 0) }
)
การสำรองและกู้คืนข้อมูลอุปกรณ์
ระบบจะจัดเก็บไฟล์ Preferences DataStore (*.preferences_pb) และไฟล์ Proto DataStore ไว้ในไดเรกทอรี files/datastore/ ของแอป โดยค่าเริ่มต้น ระบบจะรวมไฟล์เหล่านี้ไว้ใน
การสำรองข้อมูลอัตโนมัติของ Android และการโอนจากอุปกรณ์หนึ่งไปยังอีกอุปกรณ์หนึ่ง (D2D)
กำหนดค่ากฎการสำรองข้อมูลสำหรับ DataStore
หาก DataStore มีค่ากำหนดที่ไม่ละเอียดอ่อน (เช่น ธีมของผู้ใช้หรือแฟล็กฟีเจอร์) พร้อมกับข้อมูลที่ละเอียดอ่อน ให้แยกค่ากำหนดเหล่านั้นออกเป็นไฟล์ DataStore ที่แตกต่างกัน และกำหนดค่า res/xml/data_extraction_rules.xml ดังนี้
<data-extraction-rules>
<cloud-backup>
<!-- Include general settings -->
<include domain="file" path="datastore/user_settings.preferences_pb"/>
<!-- Exclude sensitive local state -->
<exclude domain="file" path="datastore/secure_state.preferences_pb"/>
</cloud-backup>
<device-to-device>
<!-- Transfer settings during device-to-device transfer -->
<include domain="file" path="datastore/"/>
</device-to-device>
</data-extraction-rules>
แสดงความคิดเห็น
แชร์ความคิดเห็นและไอเดียกับเราผ่านแหล่งข้อมูลต่อไปนี้
- เครื่องมือติดตามปัญหา:
- รายงานปัญหาเพื่อให้เราแก้ไขข้อบกพร่องได้
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Jetpack DataStore ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้
ตัวอย่าง
บล็อก
Codelab
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- โหลดและแสดงข้อมูลแบบแบ่งหน้า
- ภาพรวมของ LiveData
- การออกแบบและการเชื่อมโยงนิพจน์