डेटास्टोर Android Jetpack का हिस्सा है.

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

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

प्राथमिकताएं DataStore और Proto DataStore

DataStore दो अलग-अलग तरीके से लागू करता है: Preferences DataStore और Proto DataStore.

  • प्राथमिकताएं DataStore कुंजियों का इस्तेमाल करके डेटा स्टोर और ऐक्सेस करता है. यह लागू करने के लिए पहले से तय स्कीमा की ज़रूरत नहीं होती और न ही इससे टाइप सेफ़्टी.
  • Proto DataStore, डेटा को कस्टम डेटा टाइप के इंस्टेंस के तौर पर सेव करता है. यह लागू करने के लिए ज़रूरी है कि आप प्रोटोकॉल का इस्तेमाल करके स्कीमा तय करें बफ़र करता है, लेकिन यह सुरक्षा.

DataStore का सही तरीके से इस्तेमाल करना

DataStore को सही तरीके से इस्तेमाल करने के लिए, हमेशा इन नियमों का ध्यान रखें:

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

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

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

सेटअप

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

डेटा स्टोर की सेटिंग

ग्रूवी

    // Preferences DataStore (SharedPreferences like APIs)
    dependencies {
        implementation "androidx.datastore:datastore-preferences:1.1.1"

        // optional - RxJava2 support
        implementation "androidx.datastore:datastore-preferences-rxjava2:1.1.1"

        // optional - RxJava3 support
        implementation "androidx.datastore:datastore-preferences-rxjava3:1.1.1"
    }

    // Alternatively - use the following artifact without an Android dependency.
    dependencies {
        implementation "androidx.datastore:datastore-preferences-core:1.1.1"
    }
    

Kotlin

    // Preferences DataStore (SharedPreferences like APIs)
    dependencies {
        implementation("androidx.datastore:datastore-preferences:1.1.1")

        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-preferences-rxjava2:1.1.1")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-preferences-rxjava3:1.1.1")
    }

    // Alternatively - use the following artifact without an Android dependency.
    dependencies {
        implementation("androidx.datastore:datastore-preferences-core:1.1.1")
    }
    

प्रोटो डेटास्टोर

ग्रूवी

    // Typed DataStore (Typed API surface, such as Proto)
    dependencies {
        implementation "androidx.datastore:datastore:1.1.1"

        // optional - RxJava2 support
        implementation "androidx.datastore:datastore-rxjava2:1.1.1"

        // optional - RxJava3 support
        implementation "androidx.datastore:datastore-rxjava3:1.1.1"
    }

    // Alternatively - use the following artifact without an Android dependency.
    dependencies {
        implementation "androidx.datastore:datastore-core:1.1.1"
    }
    

Kotlin

    // Typed DataStore (Typed API surface, such as Proto)
    dependencies {
        implementation("androidx.datastore:datastore:1.1.1")

        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-rxjava2:1.1.1")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-rxjava3:1.1.1")
    }

    // Alternatively - use the following artifact without an Android dependency.
    dependencies {
        implementation("androidx.datastore:datastore-core:1.1.1")
    }
    
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है

Preferences DataStore के साथ की-वैल्यू पेयर को स्टोर करें

प्राथमिकताओं का डेटा स्टोर लागू करने की प्रक्रिया में, इन चीज़ों का इस्तेमाल किया जाता है: DataStore और Preferences क्लास की मदद से, डिस्क में सिंपल की-वैल्यू पेयर बनाए रख सकते हैं.

प्राथमिकताएं DataStore बनाएं

Datastore<Preferences> का इंस्टेंस बनाने के लिए, preferencesDataStore के बनाए गए प्रॉपर्टी डेलिगेट का इस्तेमाल करें. इसे अपनी kotlin फ़ाइल के टॉप लेवल पर एक बार कॉल करें और अपने बाकी ऐप्लिकेशन में इसे इस प्रॉपर्टी के ज़रिए ऐक्सेस करें. इससे DataStore को सिंगलटन के तौर पर रखना आसान हो जाता है. इसके अलावा, RxPreferenceDataStoreBuilder का इस्तेमाल करें का इस्तेमाल करें. ज़रूरी name पैरामीटर प्राथमिकताएं DataStore.

Kotlin

// At the top level of your kotlin file:
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")

Java

RxDataStore<Preferences> dataStore =
  new RxPreferenceDataStoreBuilder(context, /*name=*/ "settings").build();

प्राथमिकताएं DataStore से पढ़ें

प्राथमिकताएं DataStore पहले से तय स्कीमा का इस्तेमाल नहीं करता. इसलिए, आपको संबंधित कुंजी टाइप फ़ंक्शन का इस्तेमाल करके, हर उस वैल्यू के लिए एक कुंजी तय की जा सकती है जिसकी आपको ज़रूरत है DataStore<Preferences> इंस्टेंस में स्टोर करें. उदाहरण के लिए, किसी पूर्णांक मान के लिए, इसका इस्तेमाल करें intPreferencesKey(). इसके बाद, DataStore.data प्रॉपर्टी Flow का इस्तेमाल करके, सेव की गई सही वैल्यू दिखाएं.

Kotlin

val EXAMPLE_COUNTER = intPreferencesKey("example_counter")
val exampleCounterFlow: Flow<Int> = context.dataStore.data
  .map { preferences ->
    // No type safety.
    preferences[EXAMPLE_COUNTER] ?: 0
}

Java

Preferences.Key<Integer> EXAMPLE_COUNTER = PreferencesKeys.int("example_counter");

Flowable<Integer> exampleCounterFlow =
  dataStore.data().map(prefs -> prefs.get(EXAMPLE_COUNTER));

प्राथमिकताओं के लिए DataStore में लिखें

प्राथमिकताएं DataStore उपलब्ध कराता है edit() यह फ़ंक्शन DataStore में लेन-देन के दौरान डेटा को अपडेट करता है. फ़ंक्शन की transform पैरामीटर में कोड का ब्लॉक स्वीकार किया जाता है, जहां वैल्यू को इस तौर पर अपडेट किया जा सकता है की ज़रूरत नहीं है. ट्रांसफ़ॉर्म ब्लॉक में मौजूद सभी कोड को एक माना जाता है लेन-देन.

Kotlin

suspend fun incrementCounter() {
  context.dataStore.edit { settings ->
    val currentCounterValue = settings[EXAMPLE_COUNTER] ?: 0
    settings[EXAMPLE_COUNTER] = currentCounterValue + 1
  }
}

Java

Single<Preferences> updateResult =  dataStore.updateDataAsync(prefsIn -> {
  MutablePreferences mutablePreferences = prefsIn.toMutablePreferences();
  Integer currentInt = prefsIn.get(INTEGER_KEY);
  mutablePreferences.set(INTEGER_KEY, currentInt != null ? currentInt + 1 : 1);
  return Single.just(mutablePreferences);
});
// The update is completed once updateResult is completed.

Proto DataStore के साथ टाइप किए गए ऑब्जेक्ट सेव करें

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

स्कीमा तय करना

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

syntax = "proto3";

option java_package = "com.example.application";
option java_multiple_files = true;

message Settings {
  int32 example_counter = 1;
}

एक Proto DataStore बनाएं

अपने टाइप किए गए डेटा को स्टोर करने के लिए Proto DataStore बनाने के दो चरण हैं ऑब्जेक्ट:

  1. Serializer<T> को लागू करने वाली क्लास तय करें, जहां T का टाइप तय किया गया है में डालें. सीरियलाइज़र क्लास, DataStore को पढ़ने और लिखने का तरीका बताती है आपका डेटा टाइप क्या है. पक्का करें कि आपने सीरियलाइज़र के लिए डिफ़ॉल्ट वैल्यू को शामिल किया है, ताकि अगर अभी तक कोई फ़ाइल नहीं बनाई गई है, तो का उपयोग किया जा सकता है.
  2. कोई इंस्टेंस बनाने के लिए, dataStore के बनाए गए प्रॉपर्टी डेलिगेट का इस्तेमाल करें DataStore<T> का है, जहां T प्रोटो फ़ाइल में बताया गया टाइप है. इसे कॉल करें एक बार आपकी कोटलिन फ़ाइल के टॉप लेवल पर आएँ और उसे इस प्रॉपर्टी से ऐक्सेस करें आपके शेष ऐप्लिकेशन में प्रतिनिधि को असाइन करते हैं. filename पैरामीटर से पता चलता है कि डेटा स्टोर करने के लिए इस्तेमाल की जाने वाली फ़ाइल का DataStore और serializer पैरामीटर DataStore को सीरियलाइज़र क्लास का नाम बताता है की परिभाषा, पहले चरण में दी गई है.

Kotlin

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) = t.writeTo(output)
}

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

Java

private static class SettingsSerializer implements Serializer<Settings> {
  @Override
  public Settings getDefaultValue() {
    Settings.getDefaultInstance();
  }

  @Override
  public Settings readFrom(@NotNull InputStream input) {
    try {
      return Settings.parseFrom(input);
    } catch (exception: InvalidProtocolBufferException) {
      throw CorruptionException(“Cannot read proto.”, exception);
    }
  }

  @Override
  public void writeTo(Settings t, @NotNull OutputStream output) {
    t.writeTo(output);
  }
}

RxDataStore<Byte> dataStore =
    new RxDataStoreBuilder<Byte>(context, /* fileName= */ "settings.pb", new SettingsSerializer()).build();

Proto DataStore से पढ़ें

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

Kotlin

val exampleCounterFlow: Flow<Int> = context.settingsDataStore.data
  .map { settings ->
    // The exampleCounter property is generated from the proto schema.
    settings.exampleCounter
  }

Java

Flowable<Integer> exampleCounterFlow =
  dataStore.data().map(settings -> settings.getExampleCounter());

किसी Proto DataStore में लिखें

Proto DataStore से updateData() यह फ़ंक्शन सेव किए गए ऑब्जेक्ट को लेन-देन के तौर पर अपडेट करता है. updateData() से आपको आपके डेटा टाइप के इंस्टेंस के रूप में, डेटा की मौजूदा स्थिति को अपडेट करता है. साथ ही, डेटा को ऐटॉमिक रीड-राइट-मॉडिफाइंग कार्रवाई में लेन-देन के रूप में इस्तेमाल किया जाता है.

Kotlin

suspend fun incrementCounter() {
  context.settingsDataStore.updateData { currentSettings ->
    currentSettings.toBuilder()
      .setExampleCounter(currentSettings.exampleCounter + 1)
      .build()
    }
}

Java

Single<Settings> updateResult =
  dataStore.updateDataAsync(currentSettings ->
    Single.just(
      currentSettings.toBuilder()
        .setExampleCounter(currentSettings.getExampleCounter() + 1)
        .build()));

सिंक्रोनस कोड में DataStore का इस्तेमाल करें

DataStore का मुख्य फ़ायदा एसिंक्रोनस एपीआई है. हालांकि, ऐसा हो सकता है कि यह काम न करे आपके आस-पास के कोड को एसिंक्रोनस में बदला जा सकता है. यह यह स्थिति तब हो सकती है, जब आप किसी मौजूदा कोड बेस के साथ काम कर रहे हों, जो सिंक्रोनस डिस्क I/O या अगर आपके पास ऐसी डिपेंडेंसी है जो एसिंक्रोनस एपीआई.

Kotlin कोरूटीन से runBlocking() कोरूटीन बिल्डर, जिससे सिंक्रोनस और एसिंक्रोनस के बीच के अंतर को कम करने में मदद मिलती है कोड. DataStore से मिले डेटा को सिंक्रोनस रूप से पढ़ने के लिए, runBlocking() का इस्तेमाल किया जा सकता है. RxJava, Flowable पर ब्लॉक करने के तरीके उपलब्ध कराता है. यहां दिए गए कोड की वजह से, कॉल नहीं किया जा सकता DataStore से डेटा वापस मिलने तक थ्रेड:

Kotlin

val exampleData = runBlocking { context.dataStore.data.first() }

Java

Settings settings = dataStore.data().blockingFirst();

यूज़र इंटरफ़ेस (यूआई) थ्रेड पर सिंक्रोनस I/O कार्रवाइयां करने से ऐसा हो सकता है एएनआर या यूज़र इंटरफ़ेस (यूआई) जैंक. आप एसिंक्रोनस रूप से DataStore से मिला डेटा:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        context.dataStore.data.first()
        // You should also handle IOExceptions here.
    }
}

Java

dataStore.data().first().subscribe();

इस तरह, DataStore एसिंक्रोनस तरीके से डेटा को पढ़ता है और उसे मेमोरी में कैश मेमोरी में सेव करता है. टास्क के पूरा होने की तारीख आगे की है runBlocking() का इस्तेमाल करके सिंक्रोनस रीड तेज़ हो सकते हैं या डिस्क I/O से बच सकते हैं संचालन को पूरी तरह से रद्द कर सकता है.

एक से ज़्यादा प्रोसेस करने वाले कोड में DataStore का इस्तेमाल करें

अलग-अलग प्रोसेस में एक ही डेटा को ऐक्सेस करने के लिए, DataStore को कॉन्फ़िगर किया जा सकता है एक ही प्रोसेस से डेटा कंसिस्टेंसी बनाए रखने की गारंटी देता है. तय सीमा में खास तौर पर, DataStore गारंटी देता है कि:

  • रीड सिर्फ़ उस डेटा को दिखाती है जो डिस्क में सेव है.
  • लिखने के बाद एक जैसा रहना.
  • लिखने के लिए एक क्रम तय किया जाता है.
  • पढ़ने को कभी भी लिखने के लिए ब्लॉक नहीं किया जाता.

किसी सेवा और गतिविधि वाले सैंपल ऐप्लिकेशन को आज़माएं:

  1. सेवा एक अलग प्रक्रिया में चल रही है और समय-समय पर डेटास्टोर

    <service
      android:name=".MyService"
      android:process=":my_process_id" />
    
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
          scope.launch {
              while(isActive) {
                  dataStore.updateData {
                      Settings(lastUpdate = System.currentTimeMillis())
                  }
                  delay(1000)
              }
          }
    }
    
  2. ऐप्लिकेशन इन बदलावों को इकट्ठा करेगा और अपने यूज़र इंटरफ़ेस (यूआई) को अपडेट करेगा

    val settings: Settings by dataStore.data.collectAsState()
    Text(
      text = "Last updated: $${settings.timestamp}",
    )
    

अलग-अलग प्रोसेस में DataStore का इस्तेमाल करने के लिए, आपको बनाना होगा MultiProcessDataStoreFactory का इस्तेमाल करके DataStore ऑब्जेक्ट को इकट्ठा करना.

val dataStore: DataStore<Settings> = MultiProcessDataStoreFactory.create(
   serializer = SettingsSerializer(),
   produceFile = {
       File("${context.cacheDir.path}/myapp.preferences_pb")
   }
)

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

@Serializable
data class Settings(
   val lastUpdate: Long
)

@Singleton
class SettingsSerializer @Inject constructor() : Serializer<Settings> {

   override val defaultValue = Settings(lastUpdate = 0)

   override suspend fun readFrom(input: InputStream): Timer =
       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()
       )
   }
}

Hilt डिपेंडेंसी का इस्तेमाल करें इंजेक्शन को पक्का करें कि हर प्रोसेस के हिसाब से आपका DataStore इंस्टेंस अलग हो:

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

सुझाव या राय दें

इन संसाधनों की मदद से, हमारे साथ अपने सुझाव, शिकायत या राय शेयर करें:

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

अन्य संसाधन

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

सैंपल

ब्लॉग

कोड लैब