Veri Deposu Android Jetpack'in bir parçasıdır.
Jetpack DataStore, anahtar/değer çiftlerini depolamanıza olanak tanıyan bir veri depolama çözümüdür. protokol ile eşlenen veya yazılan nesne tamponlar ekleyin. DataStore, Kotlin kullanıyor eş yordamlar ve Akış, verileri eşzamansız, tutarlı ve sağlayabilir.
Mevcut bir
SharedPreferences
-
veri depoluyorsanız bunun yerine DataStore'a taşımayı düşünebilirsiniz.
DataStore ve Proto DataStore tercihleri
DataStore, iki farklı uygulama sunar: Tercihler DataStore ve Proto DataStore.
- Tercihler DataStore, verileri depolar ve anahtarları kullanarak verilere erişir. Bu uygulama, önceden tanımlanmış bir şema gerektirmez ve yazın.
- Proto DataStore, verileri özel bir veri türünün örnekleri olarak depolar. Bu uygulama, protokolü kullanarak bir şema tanımlamanızı gerektirir: arabelleklere eklenir, ancak tür yardımcı olur.
DataStore'u doğru şekilde kullanma
DataStore'u doğru şekilde kullanmak için aşağıdaki kurallara her zaman dikkat edin:
Belirli bir dosya için hiçbir zaman
DataStore
öğesinin birden fazla örneğini oluşturma gerekir. Aksi takdirde DataStore işlevselliği bozulabilir. Varsa işlemde belirli bir dosya için birden çok DataStore etkinse DataStore, verileri okurken veya güncellerkenIllegalStateException
komutunu çalıştırın.DataStore'un genel türü
sabit olmalıdır. Bir türü değiştirme DataStore'da kullanılanlar, DataStore'un sağladığı ve oluşturduğu tüm garantileri geçersiz kılar yakalanması zor hatalar belirlemelisiniz. Optimum kampanya performansı için sabitlik garantileri, basit bir API ve verimli bir serileştirme sürecidir.SingleProcessDataStore
veMultiProcessDataStore
kullanımlarını hiçbir zaman karıştırma oluşturduğunuzdan emin olun.DataStore
hizmetine birden fazla cihazdan erişmeyi düşünüyorsanız işlemi için her zamanMultiProcessDataStore
kullanın.
Kurulum
Uygulamanızda Jetpack DataStore'u kullanmak için aşağıdakini Gradle dosyanıza ekleyin bağlı olarak şunları yapabilirsiniz:
Tercihler Veri Deposu
Eski
// 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") }
Proto DataStore
Eski
// 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") }
Anahtar/değer çiftlerini Preferences DataStore ile depolama
Tercihler DataStore uygulaması,
DataStore
ve
Preferences
sınıfları kullanmanızı öneririz.
Tercihler DataStore oluşturma
Datastore<Preferences>
örneği oluşturmak için preferencesDataStore
tarafından oluşturulan mülk yetkilendirmesini kullanın. Kotlin dosyanızın en üst düzeyinde bir kez çağırıp uygulamanızın geri kalanında bu mülk üzerinden bu koda erişin. Bu sayede, DataStore
verilerinizi daha kolay bir şekilde tek bir yerde tutabilirsiniz. Alternatif olarak RxPreferenceDataStoreBuilder
da kullanılabilir.
veya RxJava kullanıyorsanız. Zorunlu name
parametresi
Tercihler 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();
Tercihler DataStore'dan okuma
Tercihler DataStore önceden tanımlanmış bir şema kullanmadığı için
her değer için bir anahtar tanımlamak üzere o değere karşılık gelen anahtar türü
DataStore<Preferences>
örneğinde depolayacağım. Örneğin, bir anahtarı tanımlamak için
bir tam sayı değeri için
intPreferencesKey()
.
Daha sonra,
DataStore.data
mülkü
için Flow
kullanarak depolanan uygun değeri gösterir.
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));
Tercihler DataStore'a yaz
Tercihler DataStore,
edit()
işlevi, DataStore
içindeki verileri işlemsel olarak güncelleyen işlevi kullanır. İşlevin
transform
parametresi, değerleri şu şekilde güncelleyebileceğiniz bir kod bloğunu kabul eder:
gerekir. Dönüşüm bloğundaki kodun tamamı tek bir kod olarak kabul edilir
belirtir.
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.
Yazılan nesneleri Proto DataStore ile depolama
Proto DataStore uygulaması DataStore ve protokol süresini kullanır. arabellekleri kalıcı hale getirmek için anlamına gelir.
Şema tanımlama
Proto DataStore,
app/src/main/proto/
dizini. Bu şema, nesnelerin türünü tanımlar
proto DataStore'da kalıcı hale getirir. Proto tanımlama hakkında daha fazla bilgi edinmek için
protobuf dili
rehberini inceleyin.
syntax = "proto3";
option java_package = "com.example.application";
option java_multiple_files = true;
message Settings {
int32 example_counter = 1;
}
Proto DataStore oluşturma
Yazdığınız verileri depolamak için Proto DataStore oluşturma işlemi iki adımdan oluşur: nesneler:
- Tanımlanan tür,
T
olanSerializer<T>
yöntemini uygulayan bir sınıf tanımlayın. emin olmanız gerekir. Bu serileştirici sınıfı DataStore'a okuma ve yazma konusunda bilgi verir veri türünüz. Serileştirici için varsayılan bir değer eklediğinizden emin olun: henüz bir dosya oluşturulmadıysa kullanılır. - Örnek oluşturmak için
dataStore
tarafından oluşturulan mülk temsilcisini kullanınDataStore<T>
; buradaT
, proto dosyasında tanımlanan türdür. Bunu ara bir kez kotlin dosyanızın en üst düzeyinde düzenleyebilir ve bu mülk aracılığıyla dosyaya erişebilirsiniz bu yetkiyi uygulamanızın tamamı boyunca kullanabilirsiniz.filename
parametresi Verilerin depolanması için kullanılacak DataStore veserializer
parametresi DataStore'a serileştirici sınıfının adını söyler tanımlanmıştır.
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'dan okuma
Depolanan nesnenizdeki uygun özelliğin Flow
öğesini göstermek için DataStore.data
kullanın.
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'a yaz
Proto DataStore, bir
updateData()
depolanan bir nesneyi işlemsel olarak güncelleyen işlevdir. updateData()
size
veri türünüzün bir örneği olarak verilerin mevcut durumunu gösterir ve
işlemsel olarak atomik bir okuma-yazma-değiştirme işleminde verilerdir.
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'u eşzamanlı kodda kullanma
DataStore'un temel avantajlarından biri eşzamansız API'dir, ancak her zaman çevrenizdeki kodu eşzamansız olacak şekilde değiştirebilirsiniz. Bu kullanan mevcut bir kod tabanıyla çalışıyorsanız eşzamanlı disk G/Ç'si sağlamayan bir bağımlılığınız varsa eşzamansız API.
Kotlin eş yordamları
runBlocking()
eşzamanlı ve eşzamansız içerikler arasındaki boşluğu kapatmaya yardımcı olacak eş yordam oluşturucu
girin. DataStore'daki verileri eşzamanlı olarak okumak için runBlocking()
kullanabilirsiniz.
RxJava, Flowable
sitesinde engelleme yöntemleri sunuyor. Aşağıdaki kod,
DataStore şu verileri döndürene kadar iş parçacığı:
Kotlin
val exampleData = runBlocking { context.dataStore.data.first() }
Java
Settings settings = dataStore.data().blockingFirst();
UI iş parçacığında eşzamanlı G/Ç işlemleri yapmak ANR'ler veya kullanıcı arayüzü duraklaması. Etiketinizi eşzamansız olarak önceden yükleyerek bu sorunları azaltabilirsiniz. verileri:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { lifecycleScope.launch { context.dataStore.data.first() // You should also handle IOExceptions here. } }
Java
dataStore.data().first().subscribe();
Bu şekilde, DataStore verileri eşzamansız olarak okur ve önbelleğe alır. Daha sonra
runBlocking()
kullanılarak eşzamanlı okuma işlemleri daha hızlı olabilir veya disk G/Ç'sinden kaçınabilir
tamamen devam eder.
DataStore'u çok işlemli kodda kullanma
DataStore'u farklı işlemlerde aynı verilere erişecek şekilde yapılandırabilirsiniz emin olmanızı sağlar. İçinde DataStore şunları garanti etmektedir:
- Okuma işlemleri yalnızca diskte tutulan verileri döndürür.
- Yazma işleminden sonra okuma tutarlılığı.
- Yazma işlemleri serileştirilir.
- Okumalar, yazma işlemleri tarafından hiçbir zaman engellenmez.
Hizmet ve etkinlik içeren örnek bir uygulamayı düşünün:
Hizmet ayrı bir işlemde çalışıyor ve Search Ads 360'taki Veri Deposu
<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) } } }
Uygulama, bu değişiklikleri toplayıp kullanıcı arayüzünü güncellerken
val settings: Settings by dataStore.data.collectAsState() Text( text = "Last updated: $${settings.timestamp}", )
DataStore'u farklı işlemlerde kullanabilmek için
MultiProcessDataStoreFactory
kullanarak DataStore nesnesini tanımlayın.
val dataStore: DataStore<Settings> = MultiProcessDataStoreFactory.create(
serializer = SettingsSerializer(),
produceFile = {
File("${context.cacheDir.path}/myapp.preferences_pb")
}
)
serializer
, DataStore'a veri türünüzü nasıl okuyacağını ve yazacağını bildirir.
Aşağıdaki durumlarda kullanılacak serileştirici için varsayılan bir değer eklediğinizden emin olun:
henüz dosya oluşturulmadı. Aşağıda, Arkadaş Bitkiler projesinin
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 bağımlılığını kullanabilirsiniz ekleyin:
@Provides
@Singleton
fun provideDataStore(@ApplicationContext context: Context): DataStore<Settings> =
MultiProcessDataStoreFactory.create(...)
Geri bildirim gönder
Aşağıdaki kaynakları kullanarak geri bildiriminizi ve düşüncelerinizi bizimle paylaşın:
- Sorun izleyici
- Hataları düzeltebilmemiz için sorunları bildirin.
Ek kaynaklar
Jetpack DataStore hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara bakın:
Örnekler
Bloglar
Codelab'ler
ziyaret edin.Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Sayfalandırılmış verileri yükleme ve görüntüleme
- LiveData'ya genel bakış
- Düzenler ve bağlama ifadeleri