DataStore   Android Jetpack का हिस्सा है.

Kotlin Multiplatform के साथ इस्तेमाल करना
Kotlin Multiplatform की मदद से, डेटा लेयर को अन्य प्लैटफ़ॉर्म के साथ शेयर किया जा सकता है. केएमपी में DataStore को सेट अप करने और इसका इस्तेमाल करने का तरीका जानें

Jetpack DataStore, डेटा स्टोरेज का एक ऐसा समाधान है जिसकी मदद से, की-वैल्यू पेयर या टाइप किए गए ऑब्जेक्ट को प्रोटोकॉल बफ़र के साथ स्टोर किया जा सकता है. DataStore, डेटा को एसिंक्रोनस, लगातार, और ट्रांज़ैक्शन के तौर पर स्टोर करने के लिए, Kotlin कोरोटीन और फ़्लो का इस्तेमाल करता है.

अगर डेटा स्टोर करने के लिए SharedPreferences का इस्तेमाल किया जा रहा है, तो DataStore पर माइग्रेट करने पर विचार करें.

DataStore API

DataStore इंटरफ़ेस, यह एपीआई उपलब्ध कराता है:

  1. एक फ़्लो जिसका इस्तेमाल, DataStore से डेटा पढ़ने के लिए किया जा सकता है

    val data: Flow<T>
    
  2. DataStore में डेटा अपडेट करने का एक फ़ंक्शन

    suspend updateData(transform: suspend (t) -> T)
    

DataStore के कॉन्फ़िगरेशन

अगर आपको कुंजियों का इस्तेमाल करके डेटा स्टोर करना है और उसे ऐक्सेस करना है, तो Preferences DataStore के लागू करने के तरीके का इस्तेमाल करें. इसके लिए, पहले से तय स्कीमा की ज़रूरत नहीं होती. साथ ही, यह टाइप की सुरक्षा की सुविधा नहीं देता. इसमें SharedPreferences जैसा एपीआई है, लेकिन इसमें शेयर की गई प्राथमिकताओं से जुड़ी कमियां नहीं हैं.

DataStore की मदद से, कस्टम क्लास को सेव किया जा सकता है. इसके लिए, आपको डेटा का स्कीमा तय करना होगा और उसे सेव किए जा सकने वाले फ़ॉर्मैट में बदलने के लिए, Serializer उपलब्ध कराना होगा. प्रोटोकॉल बफ़र, JSON या किसी अन्य सीरियलाइज़ेशन रणनीति का इस्तेमाल किया जा सकता है.

सेटअप

अपने ऐप्लिकेशन में Jetpack DataStore का इस्तेमाल करने के लिए, अपनी Gradle फ़ाइल में यह जानकारी जोड़ें. यह इस बात पर निर्भर करता है कि आपको कौनसे लागू करने के तरीके का इस्तेमाल करना है:

Preferences DataStore

将以下代码行添加到 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 支持,请添加以下依赖项:

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

将以下代码行添加到 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")
    }
    

如需支持 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 का सही तरीके से इस्तेमाल करने के लिए, इन नियमों का हमेशा ध्यान रखें:

  1. एक ही प्रोसेस में, किसी दी गई फ़ाइल के लिए DataStore का एक से ज़्यादा इंस्टेंस कभी न बनाएं. ऐसा करने से, DataStore की सभी सुविधाएं काम करना बंद कर सकती हैं. अगर एक ही प्रोसेस में, किसी दी गई फ़ाइल के लिए एक से ज़्यादा DataStore चालू हैं, तो डेटा पढ़ने या अपडेट करने पर, DataStore, IllegalStateException दिखाएगा.

  2. का सामान्य टाइप, बदला नहीं जा सकने वाला होना चाहिए.DataStore<T> DataStore में इस्तेमाल किए गए टाइप में बदलाव करने से, DataStore की ओर से दी जाने वाली स्थिरता खत्म हो जाती है. साथ ही, ऐसी गड़बड़ियां हो सकती हैं जिन्हें ठीक करना मुश्किल हो सकता है. हमारा सुझाव है कि प्रोटोकॉल बफ़र का इस्तेमाल करें. इससे, यह पक्का करने में मदद मिलती है कि डेटा में बदलाव न किया जा सके. साथ ही, इससे साफ़ एपीआई और असरदार सीरियलाइज़ेशन की सुविधा मिलती है.

  3. एक ही फ़ाइल के लिए, SingleProcessDataStore और MultiProcessDataStore के इस्तेमाल को न मिलाएं. अगर आपको DataStore को एक से ज़्यादा प्रोसेस से ऐक्सेस करना है, तो आपको MultiProcessDataStore का इस्तेमाल करना होगा.

डेटा की परिभाषा

Preferences DataStore

ऐसी कुंजी तय करें जिसका इस्तेमाल, डेटा को डिस्क पर सेव करने के लिए किया जाएगा.

val EXAMPLE_COUNTER = intPreferencesKey("example_counter")

JSON DataStore

JSON DataStore के लिए, उस डेटा में @Serialization एनोटेशन जोड़ें जिसे आपको सेव करना है.

@Serializable
data class Settings(
    val exampleCounter: Int
)

ऐसी क्लास तय करें जो Serializer<T> को लागू करती है. यहां T, उस क्लास का टाइप है जिसमें आपने पहले एनोटेशन जोड़ा था. पक्का करें कि आपने सीरियलाइज़र के लिए डिफ़ॉल्ट वैल्यू शामिल की हो, ताकि अगर अब तक कोई फ़ाइल नहीं बनाई गई है, तो उसका इस्तेमाल किया जा सके.

object SettingsSerializer : Serializer<Settings> {

    override val defaultValue: Settings = Settings(exampleCounter = 0)

    override suspend fun readFrom(input: InputStream): Settings =
        try {
            Json.decodeFromString<Settings>(
                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(t)
                .encodeToByteArray()
        )
    }
}

Proto DataStore

Proto DataStore को लागू करने के लिए, टाइप किए गए ऑब्जेक्ट को डिस्क पर सेव करने के लिए, DataStore और प्रोटोकॉल बफ़र का इस्तेमाल किया जाता है.

Proto DataStore के लिए, app/src/main/proto/ डायरेक्ट्री में मौजूद किसी proto फ़ाइल में, पहले से तय स्कीमा की ज़रूरत होती है. यह स्कीमा, उन ऑब्जेक्ट के टाइप को तय करता है जिन्हें Proto DataStore में सेव किया जाता है. proto स्कीमा तय करने के बारे में ज़्यादा जानने के लिए, protobuf भाषा की गाइड देखें.

src/main/proto फ़ोल्डर में, settings.proto नाम की एक फ़ाइल जोड़ें:

syntax = "proto3";

option java_package = "com.example.datastore.snippets.proto";
option java_multiple_files = true;

message Settings {
  int32 example_counter = 1;
}

ऐसी क्लास तय करें जो Serializer<T> को लागू करती है. यहां T वह टाइप है जिसे proto फ़ाइल में तय किया गया है . यह सीरियलाइज़र क्लास तय करती है कि DataStore, आपके डेटा टाइप को कैसे पढ़ता और लिखता है. पक्का करें कि आपने सीरियलाइज़र के लिए डिफ़ॉल्ट वैल्यू शामिल की हो, ताकि अगर अब तक कोई फ़ाइल नहीं बनाई गई है, तो उसका इस्तेमाल किया जा सके.

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<T>` का इंस्टेंस बनाने के लिए, dataStore से बनाए गए प्रॉपर्टी डेलिगेट का इस्तेमाल करें. यहां T, सीरियलाइज़ किया जा सकने वाला डेटा क्लास है.DataStore<T> इसे अपनी Kotlin फ़ाइल के टॉप लेवल पर एक बार कॉल करें और अपने ऐप्लिकेशन के बाकी हिस्से में, इस प्रॉपर्टी डेलिगेट के ज़रिए इसे ऐक्सेस करें. fileName पैरामीटर, DataStore को बताता है कि डेटा स्टोर करने के लिए किस फ़ाइल का इस्तेमाल करना है. वहीं, serializer पैरामीटर, DataStore को पहले से तय सीरियलाइज़र क्लास का नाम बताता है.

val Context.dataStore: DataStore<Settings> by dataStore(
    fileName = "settings.json",
    serializer = SettingsSerializer,
)

Proto DataStore

DataStore<T> का इंस्टेंस बनाने के लिए, dataStore से बनाए गए प्रॉपर्टी डेलिगेट का इस्तेमाल करें. यहां T, proto फ़ाइल में तय किया गया टाइप है. इसे अपनी Kotlin फ़ाइल के टॉप लेवल पर एक बार कॉल करें और अपने ऐप्लिकेशन के बाकी हिस्से में, इस प्रॉपर्टी डेलिगेट के ज़रिए इसे ऐक्सेस करें. fileName पैरामीटर, DataStore को बताता है कि डेटा स्टोर करने के लिए किस फ़ाइल का इस्तेमाल करना है. वहीं, serializer पैरामीटर, DataStore को पहले से तय सीरियलाइज़र क्लास का नाम बताता है.

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

सेव किए गए ऑब्जेक्ट से, सही प्रॉपर्टी का Flow दिखाने के लिए, DataStore.data का इस्तेमाल करें.

fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings ->
    settings.exampleCounter
}

Proto DataStore

सेव किए गए ऑब्जेक्ट से, सही प्रॉपर्टी का Flow दिखाने के लिए, DataStore.data का इस्तेमाल करें.

fun counterFlow(): Flow<Int> = context.dataStore.data.map { settings ->
    settings.exampleCounter
}

कंपोज़ेबल में, ViewModel से जनरेट किए गए Flow का इस्तेमाल करने के लिए, collectAsStateWithLifecycle का इस्तेमाल करें. इससे, DataStore Flow को Compose State में सुरक्षित तरीके से बदला जाता है. इससे, रीकंपोज़िशन ट्रिगर होता है.

@Composable
fun SomeScreen(counterFlow: Flow<Int>) {
  val counter by counterFlow.collectAsStateWithLifecycle(initialValue = 0)
  Text(text = "Example counter: ${counter}")
}

collectAsStateWithLifecycle के बारे में ज़्यादा जानने के लिए, स्टेट और 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.copy { exampleCounter = exampleCounter + 1 }
    }
}

Compose ऐप्लिकेशन में DataStore का इस्तेमाल करना

Compose ऐप्लिकेशन में DataStore का इस्तेमाल करने के लिए, Android ऐप्लिकेशन आर्किटेक्चर के दिशा-निर्देशों का पालन करें. इसके लिए, DataStore के ऑपरेशन को अपनी डेटा लेयर (जैसे, रिपॉज़िटरी) में रखें और ViewModel के ज़रिए अपने यूज़र इंटरफ़ेस (यूआई) को डेटा दिखाएं.

अपने कंपोज़ेबल फ़ंक्शन में, DataStore से सीधे डेटा पढ़ने या उसमें डेटा सेव करने से बचें.

  1. ViewModel के ज़रिए DataStore को दिखाएं. अपनी रिपॉज़िटरी (जिसमें DataStore रैप किया गया है) को अपने ViewModel में पास करें और Flow को StateFlow में बदलें, ताकि यूआई इसे आसानी से देख सके. इसके लिए, यहां दिया गया स्nippet देखें:

    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)
            }
        }
    }
    
  2. अपने कंपोज़ेबल से देखें और लिखें. अपने यूआई में StateFlow को सुरक्षित तरीके से देखने के लिए, collectAsStateWithLifecycle का इस्तेमाल करें. साथ ही, लिखने की प्रोसेस को मैनेज करने के लिए, 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
)

सीरियलाइज़र, DataStore को बताता है कि आपके डेटा टाइप को कैसे पढ़ना और लिखना है. पक्का करें कि आपने सीरियलाइज़र के लिए डिफ़ॉल्ट वैल्यू शामिल की हो, ताकि अगर अब तक कोई फ़ाइल नहीं बनाई गई है, तो उसका इस्तेमाल किया जा सके. यहां kotlinx.serialization का इस्तेमाल करके, लागू करने का एक उदाहरण दिया गया है:

object TimeSerializer : Serializer<Time> {

    override val defaultValue: Time = Time(lastUpdateMillis = 0L)

    override suspend fun readFrom(input: InputStream): Time =
        try {
            Json.decodeFromString<Time>(
                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(t)
                .encodeToByteArray()
        )
    }
}

अलग-अलग प्रोसेस में DataStore का इस्तेमाल करने के लिए, आपको ऐप्लिकेशन और सेवा, दोनों के कोड के लिए MultiProcessDataStoreFactory का इस्तेमाल करके, DataStore ऑब्जेक्ट बनाना होगा:

val dataStore = MultiProcessDataStoreFactory.create(
    serializer = TimeSerializer,
    produceFile = {
        File("${context.filesDir.path}/time.pb")
    },
    corruptionHandler = null
)

अपने AndroidManifiest.xml में यह जानकारी जोड़ें:

<service
    android:name=".TimestampUpdateService"
    android:process=":my_process_id" />

सेवा, समय-समय पर updateLastUpdateTime को कॉल करती है. इससे, updateData का इस्तेमाल करके, DataStore में डेटा सेव किया जाता है.

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 डिपेंडेंसी इंजेक्शन का इस्तेमाल किया जा सकता है, ताकि हर प्रोसेस के लिए आपका DataStore इंस्टेंस यूनीक हो:

@Provides
@Singleton
fun provideDataStore(@ApplicationContext context: Context): DataStore<Settings> =
   MultiProcessDataStoreFactory.create(...)

फ़ाइल के करप्ट होने की समस्या को ठीक करना

कभी-कभी, DataStore की डिस्क पर सेव की गई फ़ाइल करप्ट हो सकती है. डिफ़ॉल्ट रूप से, DataStore करप्ट हुई फ़ाइल को अपने-आप ठीक नहीं करता. साथ ही, इससे डेटा पढ़ने की कोशिश करने पर, सिस्टम CorruptionException दिखाएगा.

DataStore, करप्शन हैंडलर एपीआई उपलब्ध कराता है. इससे, इस तरह की स्थिति में, डेटा को सुरक्षित तरीके से वापस पाने में मदद मिल सकती है. साथ ही, इससे एक्सेप्शन को रोका जा सकता है. कॉन्फ़िगर करने पर, करप्शन हैंडलर, करप्ट हुई फ़ाइल को नई फ़ाइल से बदल देता है. इस नई फ़ाइल में, पहले से तय डिफ़ॉल्ट वैल्यू होती है.

इस हैंडलर को सेट अप करने के लिए, by dataStore में या DataStoreFactory फ़ैक्ट्री के तरीके में, DataStore इंस्टेंस बनाते समय, corruptionHandler उपलब्ध कराएं:

val dataStore: DataStore<Settings> = DataStoreFactory.create(
   serializer = SettingsSerializer(),
   produceFile = {
       File("${context.filesDir.path}/myapp.preferences_pb")
   },
   corruptionHandler = ReplaceFileCorruptionHandler { Settings(lastUpdate = 0) }
)

सुझाव/राय दें या शिकायत करें

इन संसाधनों के ज़रिए, अपने सुझाव, शिकायत या राय और आइडिया हमारे साथ शेयर करें:

समस्या को ट्रैक करने वाला टूल:
समस्याओं की रिपोर्ट करें, ताकि हम गड़बड़ियों को ठीक कर सकें.

अन्य संसाधन

Jetpack DataStore के बारे में ज़्यादा जानने के लिए, यहां दिए गए अन्य संसाधन देखें:

सैंपल

ब्लॉग

कोडलैब