Kullanıcı arayüzü katmanı, kullanıcı arayüzüyle ilgili durum ve kullanıcı arayüzü mantığı içerse de veri katmanı uygulama verilerini ve iş mantığını içerir. İş mantığı uygulamanıza değer katar. Uygulamanız, uygulamanızı ve oyununuzu Uygulama verilerinin nasıl oluşturulması, depolanması ve değiştirilmesi gerektiği.
Endişelerin bu şekilde ayrılması, veri katmanının birden fazla uygulamanın farklı bölümleri arasında bilgi paylaşımına ve iş mantığını tanımlamaya çalışın. Daha fazla bilgi için avantajları hakkında daha fazla bilgi için Mimariye Genel Bakış öğrenin.
Veri katmanı mimarisi
Veri katmanı, her biri sıfır ile çok sayıda arasında yer alabilecek depolardan oluşur.
veri kaynakları için de geçerlidir. Her farklı tür için bir depo sınıfı oluşturmanız gerekir.
verileri de kapsar. Örneğin, bir MoviesRepository
filmlerle ilgili veriler için bir sınıf veya veriler için bir PaymentsRepository
sınıfı
ödemelerle ilgilidir.
Depo sınıfları aşağıdaki görevlerden sorumludur:
- Veriler, uygulamanın geri kalanına sunuluyor.
- Verilerdeki değişiklikleri merkezileştirme.
- Birden fazla veri kaynağı arasındaki çakışmaları çözme.
- Uygulamanın geri kalanından veri kaynaklarının soyutlanması.
- İş mantığı içerir.
Her veri kaynağı sınıfı, tek bir veri kaynağı sınıfıyla çalışma sorumluluğuna sahip olmalıdır. Bir dosya, ağ kaynağı veya yerel veritabanı olabilir. Veri kaynak sınıfları, uygulama ile veri sistemi arasındaki köprüdür anlamına gelir.
Hiyerarşideki diğer katmanlar hiçbir zaman veri kaynaklarına doğrudan erişmemelidir; "the" her zaman depo sınıflarıdır. Eyalet sahibi sınıfları (Kullanıcı Arayüzü katmanı kılavuzuna bakın) veya büyük/küçük harf sınıfları (alan katmanı kılavuzuna bakın) hiçbir zaman doğrudan bağımlılık olarak bir veri kaynağına sahip değildir. Depo sınıflarını şu şekilde kullanma: giriş noktaları, mimarinin farklı katmanlarının ölçeklenmesine olanak sağlar bağımsız olarak değiştirebilirsiniz.
Bu katmanın açığa çıkardığı veriler sabit olmalıdır. Böylece, kurcalar; bu da onun değerlerini açıkça ortaya koyan tutarsız duruma gelir. Sabit veriler ayrıca, birden çok kişi tarafından güvenli bir şekilde işlenebilir. ileti dizileri. Daha fazla bilgi için ileti dizisi bölümünü inceleyin.
Bağımlılık yerleştirme ile ilgili en iyi uygulamaları izleyerek depo, oluşturucusunda veri kaynaklarını bağımlılık olarak alır:
class ExampleRepository(
private val exampleRemoteDataSource: ExampleRemoteDataSource, // network
private val exampleLocalDataSource: ExampleLocalDataSource // database
) { /* ... */ }
API'leri kullanıma sunun
Veri katmanındaki sınıflar genellikle tek seferlik oluşturma, Okuma, Güncelleme ve Silme (CRUD) aramalarını veya mevcut veri değişikliklerinden haberdar olmak için gerekir. Veri katmanı, bu durumların her biri için aşağıdakileri göstermelidir:
- Tek seferlik işlemler: Veri katmanı, askıya alma işlevlerini
Kotlin; Java programlama dili için ise veri katmanı
işlemin sonucunu bildirmek için bir geri çağırma sağlayan işlevler veya
RxJava
Single
,Maybe
veyaCompletable
türleri. - Zaman içindeki veri değişiklikleriyle ilgili bildirim almak için: Veri katmanı,
Kotlin'deki akışlar; Java programlama dili için
veri katmanında, yeni veriler yayan bir geri çağırmanın veya RxJava'nın
Observable
veyaFlowable
türü.
class ExampleRepository(
private val exampleRemoteDataSource: ExampleRemoteDataSource, // network
private val exampleLocalDataSource: ExampleLocalDataSource // database
) {
val data: Flow<Example> = ...
suspend fun modifyData(example: Example) { ... }
}
Bu kılavuzdaki adlandırma kuralları
Bu kılavuzda depo sınıfları, kullandıkları verilerden çok önemli. Kural aşağıdaki gibidir:
veri türü + Depo.
Örneğin: NewsRepository
, MoviesRepository
veya PaymentsRepository
.
Veri kaynağı sınıfları, sorumlu oldukları verilerin ve yardımcı olur. Kural aşağıdaki gibidir:
veri türü + kaynak türü + Veri Kaynağı.
Veri türü olarak daha genel olması için Uzaktan veya Yerel değerini kullanın, çünkü
değişiklik gösterebiliyor. Örneğin: NewsRemoteDataSource
veya
NewsLocalDataSource
. Kaynağın önemli olduğu durumlarda daha net bilgi vermek için
kaynağın türünü seçin. Örneğin: NewsNetworkDataSource
veya
NewsDiskDataSource
.
Veri kaynağını bir uygulama ayrıntısına göre adlandırmayın (örneğin,
UserSharedPreferencesDataSource
—çünkü bu veri kaynağını kullanan depolar
verilerin nasıl kaydedildiğini bilmemelidir. Bu kurala uyarsanız aşağıdakileri değiştirebilirsiniz:
uygulama (örneğin, Google Cloud'dan
SharedPreferences (PaylaşılanTercihler)
DataStore)
katmanıdır.
Birden çok depo seviyesi
Daha karmaşık iş gereksinimleri içeren bazı durumlarda depo ve diğer depolara bağlı olmaları gerekir. Bunun nedeni, kullanılan verilerin birden çok veri kaynağından toplaması veya sorumluluğun başka bir depo sınıfına kapsüllenir.
Örneğin, kullanıcı kimlik doğrulama verilerini işleyen bir depo,
UserRepository
, LoginRepository
gibi diğer depolara bağlı olabilir
ve RegistrationRepository
gibi hizmetlerden yararlanabilirsiniz.
Doğru bilginin kaynağı
Her bir deponun tek bir veri kaynağını tanımlaması önemlidir. Kaynak her zaman tutarlı, doğru ve güncel veriler içerir. İçinde depodan açığa çıkarılan veriler, her zaman gelecekteki veriler olmalıdır. doğrudan veri kaynağından alınır.
Doğru bilgi kaynağı bir veri kaynağı (ör. veritabanı) hatta veri kaynağı içerebilecek önbellekteki bellek içi önbelleği gösterir. Kod depoları birleştirme yardımcı olur ve veriler arasındaki olası çakışmaları giderir. tek doğru kaynağı düzenli olarak güncellemeye veya bir kullanıcı girişine bağlı olarak güncelleme kaynaklarının unutmayın.
Uygulamanızdaki farklı depoların farklı bilgi kaynakları olabilir. Örneğin,
örnek olarak, LoginRepository
sınıfı bilgi kaynağı olarak kendi önbelleğini kullanabilir.
ve PaymentsRepository
sınıfı, ağ veri kaynağını kullanabilir.
Çevrimdışı öncelikli destek sağlamak için yerel bir veri kaynağı (ör. veritabanı—önerilen veri kaynağıdır.
İleti dizisi
Veri kaynakları ve depoları ana güvenli olmalıdır, yani güvenli bir şekilde arama yapılabilir takip edebilirsiniz. Bu sınıflar, şubelerin yürütülmesinin uzun süreli engelleme gerçekleştirirken uygun iş parçacığının mantığına göre anlamına gelir. Örneğin, bir veri kaynağının büyük bir listede pahalı filtreleme yapması olabilir.
Çoğu veri kaynağının askıya alma gibi ana güvenli API'ler sağladığını unutmayın. Room tarafından sağlanan yöntem çağrıları Geriye dönük veya Ktor. Deponuz; bu API'lerden yararlanabilirsiniz.
İleti dizisi oluşturma hakkında daha fazla bilgi edinmek için arka plan kılavuzuna bakın. işleniyor. Kotlin kullanıcıları için: eş yordamlar önerilen seçenektir. Bkz. Koşu Arka plandaki iş parçacıklarında Android görevleri önerilen seçenekleri kullanabilirsiniz.
Yaşam döngüsü
Veri katmanındaki sınıfların örnekleri, bir atık toplama kökünden erişilebilir (genellikle nesne olarak kabul edilir.
Sınıfta bellek içi veriler (ör. önbellek) varsa bu verileri yeniden kullanmak isteyebilirsiniz. belirli bir süre boyunca bu sınıfın aynı örneğinin olması gerekir. Bu ayrıca bu aşama, sınıf örneğinin yaşam döngüsü olarak adlandırılır.
Sınıfın sorumluluğu tüm başvuru için çok önemliyse
kapsamını bu sınıfın bir örneğini Application
sınıfına kapsar. Bu da,
örnek, uygulamanın yaşam döngüsünü izler. Alternatif olarak
Aynı örneği uygulamanızdaki belirli bir akışta tekrar kullanmanız gerekiyorsa (örneğin,
kayıt veya giriş akışı. Örneği sınıfa kapsamanız gerekir.
o akışın yaşam döngüsüne
sahip olan başka bir uzantıdır. Örneğin, Arkadaş Bitkiler projenizde
Şuraya bellek içi veri içeren RegistrationRepository
:
RegistrationActivity
veya gezinme
grafiğin
her şeyi kapsayabilir.
Her bir örneğin yaşam döngüsü, nasıl sunacağınıza karar vermede tespit etmenize yardımcı olur. bağımlılığı en iyi uygulamaları arasına alarak yönetilir ve bağımlılık kapsayıcılarına dahil edilebilir. Şu konu hakkında daha fazla bilgi edinmek için: Android'de Kapsam oluşturma ve Sap blog yayınımıza göz atın.
İş modellerini temsil etme
Veri katmanından göstermek istediğiniz veri modelleri, farklı veri kaynaklarından aldığınız bilgilerdir. İdeal olarak Ağ ve yerel gibi farklı veri kaynakları yalnızca bilgileri döndürmelidir uygulama ihtiyaçlarınız; ancak bu durum pek sık yaşanmamaktadır.
Örneğin, yalnızca makale makalelerini değil, aynı zamanda geçmişi, kullanıcı yorumlarını ve bazı meta verileri de düzenleyebilirsiniz.
data class ArticleApiModel(
val id: Long,
val title: String,
val content: String,
val publicationDate: Date,
val modifications: Array<ArticleApiModel>,
val comments: Array<CommentApiModel>,
val lastModificationDate: Date,
val authorId: Long,
val authorName: String,
val authorDateOfBirth: Date,
val readTimeMin: Int
)
Uygulamanın makaleyle ilgili çok fazla bilgiye ihtiyacı yoktur çünkü
temel bilgilerle birlikte ekranda makalenin içeriğini gösterir
e-posta yazacaksınız. Model sınıflarını ayırıp
depoları yalnızca hiyerarşinin diğer katmanlarının gösterdiği verileri açığa çıkarır
gerekir. Örneğin, şu şekilde kırparak ArticleApiModel
alan adına ve kullanıcı arayüzüne bir Article
model sınıfını göstermek için ağı
katmanlar:
data class Article(
val id: Long,
val title: String,
val content: String,
val publicationDate: Date,
val authorName: String,
val readTimeMin: Int
)
Model sınıflarını ayırmak şu açılardan faydalıdır:
- Gereken verileri azaltarak uygulama belleğinden tasarruf eder.
- Harici veri türlerini, uygulamanızın kullandığı veri türlerine uyarlar. Örneğin, uygulaması, tarihleri temsil etmek için farklı bir veri türü kullanıyor olabilir.
- Endişelerin daha iyi ayrılmasını sağlar (örneğin, büyük bir ekibin üyeleri) model, bir özelliğin ağ ve kullanıcı arayüzü katmanlarında ayrı ayrı çalışabilir. önceden tanımlandığından emin olun.
Bu uygulamanın kapsamını genişleterek, projenizin diğer bölümlerinde de ayrı model sınıfları tanımlayabilirsiniz. uygulama mimariniz de (ör. veri kaynağı sınıflarında ViewModelleri'ni tıklayın. Ancak bu, iş kırılım yapılarını dahil etmek için belgelemeli ve test etmelisiniz. En azından şunu yapmanız önerilir: bir veri kaynağının verileri size göndermeyeceği her durumda yeni modeller aynı olmasını sağlayabilirsiniz.
Veri işlemi türleri
Veri katmanı, ne kadar kritik olduğuna göre değişen işlem türleriyle başa çıkabilir Kullanıcı arayüzü, uygulama ve iş odaklı operasyonlar.
Kullanıcı arayüzü odaklı işlemler
Kullanıcı arayüzü odaklı işlemler, yalnızca kullanıcı belirli bir ekrandayken alakalıdır. Kullanıcı ekrandan ayrıldığında ise iptaller iptal edilir. Örneğin, veri tabanından alınan bazı verilerin görüntülenmesidir.
Kullanıcı arayüzü odaklı işlemler genellikle kullanıcı arayüzü katmanı tarafından tetiklenir ve arayanın yaşam döngüsü (örneğin, ViewModel'in yaşam döngüsü). Daha fazla bilgi için ağ isteği bölümü, kullanıcı arayüzü odaklı işlemidir.
Uygulama odaklı işlemler
Uygulama odaklı işlemler, uygulama açık olduğu sürece önemlidir. Uygulama: veya işlem sonlandırılırsa bu işlemler iptal edilir. Örneğin, daha sonra gerektiğinde kullanılabilmesi için bir ağ isteğinin sonucunu önbelleğe alma. Bilgi edinmek için Bellek içi verileri önbelleğe almayı uygulama bölümüne bakın daha fazla.
Bu işlemler genellikle Application
sınıfının veya
veri katmanından yararlanın. Örneğin, Bir işlemin
ekran bölümüne bakın.
İş odaklı operasyonlar
İş odaklı işlemler iptal edilemez. Değişimin ve süreç içinde ölümcül olabilir. Örneğin, kullanıcının yayınlamak istediği bir fotoğrafın yüklenmesinin tamamlanması verilebilir tercih edebilirsiniz.
İş odaklı işlemler için WorkManager'ı kullanmanız önerilir. Görüntüleyin Daha fazla bilgi edinmek için WorkManager'ı kullanarak görev planlama bölümüne bakın.
Hataları kullanıma sunun
Depo ve veri kaynaklarıyla etkileşimler başarılı veya
bir istisna oluşturur. Eş yordamlar ve akışlar için
Kotlin'in yerleşik hata işleme
mekanizmasını inceleyin. Örneğin,
veya askıya alma işlevleri tarafından tetiklenebilecek hatalar, aşağıdaki durumlarda try/catch
bloklarını kullanın:
uygun olmalıdır; akışlarda
catch
operatörümüzü kullanabilirsiniz. Bu yaklaşımla, kullanıcı arayüzü katmanının aşağıdaki durumlarda istisnaları işlemesi beklenir:
veri katmanını çağırır.
Veri katmanı, farklı hata türlerini anlayıp işleyebilir ve
bunları UserNotAuthenticatedException
gibi özel istisnalar kullanarak gösterebilirsiniz.
Eş yordamlardaki hatalar hakkında daha fazla bilgi edinmek için eş yordamlar blog yayınımıza göz atın.
Genel görevler
Aşağıdaki bölümlerde, verilerin nasıl kullanılacağı ve mimarisiyle ilgili örnekler verilmiştir. katmanını kullanabilirsiniz. Örnekler: temel alınmıştır.
Ağ isteğinde bulunma
Ağ isteğinde bulunmak, bir Android uygulamasının yapabileceği en yaygın görevlerden biridir.
yardımcı olur. Haber uygulaması, kullanıcıya güncel haberleri sunmalıdır.
ağdan getirilir. Bu nedenle, uygulamanın yönetilebilmesi için bir veri kaynağı sınıfına ihtiyacı vardır.
ağ işlemleri: NewsRemoteDataSource
. Bilgileri
uygulamanın geri kalanında, haber verileriyle ilgili
işlemleri yapan yeni bir depo
oluşturulma tarihi: NewsRepository
.
Bu şart, kullanıcı en son haberlerin kullanıcı tarafından ekranı açar. Bu nedenle, bu kullanıcı arayüzü odaklı bir işlemdir.
Veri kaynağını oluşturma
Veri kaynağının en son haberleri döndüren bir işlevi göstermesi gerekir: liste
/ArticleHeadline
örnek. Veri kaynağının ana güvenli bir yol sağlaması gerekir
ağdan en son haberleri almak için. Bunun için önce
bağımlılığı yoktur.CoroutineDispatcher
Executor
Ağ isteği, yeni bir fetchLatestNews()
tarafından ele alınan tek seferlik bir aramadır
yöntem:
class NewsRemoteDataSource(
private val newsApi: NewsApi,
private val ioDispatcher: CoroutineDispatcher
) {
/**
* Fetches the latest news from the network and returns the result.
* This executes on an IO-optimized thread pool, the function is main-safe.
*/
suspend fun fetchLatestNews(): List<ArticleHeadline> =
// Move the execution to an IO-optimized thread since the ApiService
// doesn't support coroutines and makes synchronous requests.
withContext(ioDispatcher) {
newsApi.fetchLatestNews()
}
}
// Makes news-related network synchronous requests.
interface NewsApi {
fun fetchLatestNews(): List<ArticleHeadline>
}
NewsApi
arayüzü, ağ API istemcisinin uygulanmasını gizler; o
arayüzün orijinal veya harici
Geriye dönük uyar veya
HttpURLConnection
. Yaklaşım:
arayüzleri, uygulamanızdaki API uygulamalarını değiştirilebilir hale getirir.
Depoyu oluşturma
Bu görev için depo sınıfında ek mantık gerekmediğinden,
NewsRepository
, ağ veri kaynağı için proxy görevi görür. Faydaları
soyutlama katmanının eklenmesiyle ilgili açıklama, in-memory
önbelleğe alma bölümüne bakın.
// NewsRepository is consumed from other layers of the hierarchy.
class NewsRepository(
private val newsRemoteDataSource: NewsRemoteDataSource
) {
suspend fun fetchLatestNews(): List<ArticleHeadline> =
newsRemoteDataSource.fetchLatestNews()
}
Kod deposu sınıfının doğrudan UI katmanından nasıl kullanılacağını öğrenmek için Kullanıcı arayüzü katmanı rehberi.
Bellek içi verileri önbelleğe almayı uygulama
Haber uygulaması için yeni bir şartın (kullanıcı sayfayı açtığında) istekte bulunulması durumunda, önbelleğe alınan haberlerin kullanıcıya sunulması gerekir öğrendi. Aksi takdirde, uygulama en yeni haberler.
Yeni şart göz önünde bulundurulduğunda uygulamanın bellekteki en son haberleri koruması gerekiyor. Kullanıcının uygulamayı açması. Bu nedenle, uygulama odaklı bir işlemdir.
Önbellek
Bellek içi veriler ekleyerek kullanıcı uygulamanızdayken verileri koruyabilirsiniz önbelleğe alma. Önbellekler, belirli bir dosyayla ilgili bazı bilgileri hafızaya kaydetmek süre (bu örnekte, kullanıcı uygulamada bulunduğu sürece) Önbellek uygulamalar farklı şekillerde olabilir. Basit bir değişkenden farklı olabilir, değişkenini okuma/yazma işlemlerinden koruyan daha gelişmiş bir sınıfa birden fazla ileti dizisinde. Kullanım alanına bağlı olarak, önbelleğe alma işlemi emin olmanız gerekir.
Ağ isteğinin sonucunu önbelleğe al
Kolaylık sağlaması açısından NewsRepository
, en yeni
haberler. Okuma ve yazma işlemlerini farklı ileti dizilerinden korumak için
Mutex
bu düzenlemelerin nedenlerinden biri. Paylaşılan değişken durum ve eşzamanlılık hakkında daha fazla bilgi edinmek için
Kotlin Dili
dokümanlarına göz atın.
Aşağıdaki uygulama, en son haber bilgilerini
Mutex
ile yazmaya karşı korumalı depo.
ağ isteği başarılı olursa veriler latestNews
değişkenine atanır.
class NewsRepository(
private val newsRemoteDataSource: NewsRemoteDataSource
) {
// Mutex to make writes to cached values thread-safe.
private val latestNewsMutex = Mutex()
// Cache of the latest news got from the network.
private var latestNews: List<ArticleHeadline> = emptyList()
suspend fun getLatestNews(refresh: Boolean = false): List<ArticleHeadline> {
if (refresh || latestNews.isEmpty()) {
val networkResult = newsRemoteDataSource.fetchLatestNews()
// Thread-safe write to latestNews
latestNewsMutex.withLock {
this.latestNews = networkResult
}
}
return latestNewsMutex.withLock { this.latestNews }
}
}
Bir işlemin ekrandan daha uzun sürmesini sağlama
Ağ isteği etkinken kullanıcı ekrandan ayrılırsa
bu işlem iptal edilir ve sonuç önbelleğe alınmaz. NewsRepository
.
bu mantığı gerçekleştirmek için arayanın CoroutineScope
kullanmamalıdır. Bunun yerine
NewsRepository
, yaşam döngüsüne bağlı bir CoroutineScope
kullanmalıdır.
En son haberleri getirmenin uygulama odaklı bir işlem olması gerekir.
Bağımlılık yerleştirmeyle ilgili en iyi uygulamaları izlemek için NewsRepository
,
oluşturmak yerine kendi oluşturucusunda bir parametre olarak kapsayabilir
CoroutineScope
. Çünkü kod depoları, gerekli işlemleri yapmak için
yoksa CoroutineScope
öğesini aşağıdakilerden biriyle yapılandırmanız gerekir:
Dispatchers.Default
veya kendi ileti dizisi havuzunuzla.
class NewsRepository(
...,
// This could be CoroutineScope(SupervisorJob() + Dispatchers.Default).
private val externalScope: CoroutineScope
) { ... }
Çünkü NewsRepository
, Google Analytics 4'teki
harici CoroutineScope
, veri kaynağına yapılan çağrıyı gerçekleştirmeli ve
şu kapsamda başlatılan yeni bir eş yordamla sonuçlandırdı:
class NewsRepository(
private val newsRemoteDataSource: NewsRemoteDataSource,
private val externalScope: CoroutineScope
) {
/* ... */
suspend fun getLatestNews(refresh: Boolean = false): List<ArticleHeadline> {
return if (refresh) {
externalScope.async {
newsRemoteDataSource.fetchLatestNews().also { networkResult ->
// Thread-safe write to latestNews.
latestNewsMutex.withLock {
latestNews = networkResult
}
}
}.await()
} else {
return latestNewsMutex.withLock { this.latestNews }
}
}
}
async
, harici kapsamda eş yordamı başlatmak için kullanılır. await
adı
ağ isteği geri gelene ve
sonuç önbelleğe kaydedilir. O zamana kadar kullanıcı hâlâ ekrandaysa
en son haberleri görürler; kullanıcı ekrandan uzaklaştığında
await
iptal edilir ancak async
içindeki mantık yürütülmeye devam eder.
Bu bloga göz atın
yayın
ve CoroutineScope
kalıpları hakkında daha fazla bilgi edinin.
Diskteki verileri kaydet ve al
Yer işareti konulan haberler ve kullanıcı tercihleri gibi verileri kaydetmek istediğinizi varsayalım. Bu tür verilerin süreç ölümünden sonra ayakta kalması ve Kullanıcı ağa bağlı değil.
Üzerinde çalıştığınız verilerin, sürecin ölümünden sonra atlatılması gerekiyorsa aşağıdaki yöntemlerden birini kullanarak diskte depolayabilirsiniz:
- Sorgulanması gereken, referans bütünlüğü gerektiren büyük veri kümeleri veya kısmi güncellemeler yapmanız gerekiyorsa verileri Oda veritabanına kaydedin. Haberler uygulamasında haber makaleleri veya yazarlar veritabanına kaydedilebilir.
- Yalnızca alınması ve ayarlanması gereken küçük veri kümeleri için (sorgular veya kısmen güncellendiyse) DataStore'u kullanın. Haberler uygulaması örneğinde, kullanıcının tercih edilen tarih biçiminin veya diğer görüntüleme tercihlerinin DataStore'u seçin.
- JSON nesnesi gibi veri parçaları için bir dosya kullanın.
Bilgi kaynağı bölümünde belirtildiği gibi, her veri
kaynak yalnızca tek bir kaynakla çalışır ve belirli bir veri türüne (
örneğin, News
, Authors
, NewsAndAuthors
veya UserPreferences
). Sınıflar
verilerin nasıl kaydedildiğini bilmemelidir. Örneğin,
emin olmanız gerekir.
Veri kaynağı olarak oda
Çünkü her veri kaynağı yalnızca tek bir veri kaynağıyla çalışma sorumluluğuna
belirli bir veri türü için bir veri kaynağı
veri erişim nesnesi (DAO) veya
parametresini kullanabilirsiniz. Örneğin NewsLocalDataSource
,
NewsDao
örneği olabilir, AuthorsLocalDataSource
ise
AuthorsDao
örneği.
Bazı durumlarda, ekstra mantık gerekmiyorsa DAO'yu doğrudan ekleyebilirsiniz. kolayca değiştirebileceğiniz bir arayüz olduğundan, DAO'nun yardımcı olur.
Oda API'leriyle çalışma hakkında daha fazla bilgi için Oda kılavuzlar.
Veri kaynağı olarak DataStore
DataStore, veri depolama çözümüyle kullanıcı ayarları gibi anahtar/değer çiftlerinden ibarettir. Örneğin saat biçimi, ve haber öğelerinin kullanıcılara gösterilmesinin ardından bu e-postaları okudu. DataStore, yazılan nesneleri protokol ile de depolayabilir: tamponlar ekleyin.
Diğer nesnelerde olduğu gibi, DataStore tarafından desteklenen bir veri kaynağında da belirli bir türe veya uygulamanın belirli bir bölümüne karşılık gelen veriler Bu bu durum DataStore ile daha da doğru sonuç verir. Bunun nedeni, DataStore okumalarının akış olarak açığa çıkmasıdır. bir değer her güncellendiğinde ortaya çıkan bir reklam öğesidir. Bu nedenle, aynı DataStore'daki ilgili tercihleri içerebilir.
Örneğin, yalnızca şu işlemleri yapan bir NotificationsDataStore
olabilir:
tercihlere ve sadece NewsPreferencesDataStore
haber ekranıyla ilgili tercihleri işler. Bu şekilde, zaman çizelgesine sadık kalmak için
çünkü yalnızca newsScreenPreferencesDataStore.data
akışı geçerli olduğundan
söz konusu ekranla ilgili bir tercih değiştirildiğinde yayımlanır. Aynı zamanda,
nesnenin yaşam döngüsü de daha kısa olabilir çünkü
haber ekranı görüntülenir.
DataStore API'leriyle çalışma hakkında daha fazla bilgi edinmek için DataStore'a göz atın kılavuzlar.
Veri kaynağı olarak dosya
JSON nesnesi veya bit eşlem gibi büyük nesnelerle çalışırken
File
nesnesiyle çalışma ve ileti dizileri arasında geçiş yapma işlemlerini gerçekleştirme.
Dosya depolama alanıyla çalışma hakkında daha fazla bilgi edinmek için bkz. Depolama alanı genel bakış sayfasını ziyaret edin.
WorkManager'ı kullanarak görevleri planlama
Haber uygulaması için başka bir yeni şartın da getirildiğini varsayalım: Uygulama kullanıcıya en son haberleri düzenli ve otomatik olarak getirme seçeneği Ancak cihaz şarj oluyor ve sınırsız bir ağa bağlı olmalıdır. Bu durum, işletme odaklı bir operasyon. Bu şart, Google'ın, reklamverenlerin Kullanıcı uygulamayı açtığında cihazın bağlantısı yoksa kullanıcı son haberleri görmeye devam edebilir.
WorkManager, şunları kolaylaştırır:
eş zamanlı olmayan, güvenilir bir iş planlaması ve kısıtların üstesinden gelebilir
üzerine konuşalım. Sürekli çalışmak için önerilen kitaplıktır. Gerçekleştirmek için
yukarıda tanımlanan göreve
Worker
sınıf oluşturuldu: RefreshLatestNewsWorker
. Bu ders NewsRepository
sürer
almak için bir bağımlılık olarak kullanabilirsiniz.
class RefreshLatestNewsWorker(
private val newsRepository: NewsRepository,
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = try {
newsRepository.refreshLatestNews()
Result.success()
} catch (error: Throwable) {
Result.failure()
}
}
Bu tür bir görevin iş mantığı, kendi sınıfında yer almalıdır. ve ayrı bir veri kaynağı olarak işlenir. WorkManager bu durumda sadece tüm kısıtlamalar olduğunda işin bir arka plan iş parçacığı üzerinde yürütülmesini sağlamak için karşılanıyor. Bu kalıba uyarak kullandığınız diğer sayfalardaki uygulamaları hızlı bir şekilde değiştirebilirsiniz. ortama uyarlayabilirsiniz.
Bu örnekte, haberlerle ilgili bu görev NewsRepository
kaynağından çağrılmalıdır.
Bu durumda bağımlılık olarak yeni bir veri kaynağı alınır: NewsTasksDataSource
,
aşağıdaki gibi uygulanır:
private const val REFRESH_RATE_HOURS = 4L
private const val FETCH_LATEST_NEWS_TASK = "FetchLatestNewsTask"
private const val TAG_FETCH_LATEST_NEWS = "FetchLatestNewsTaskTag"
class NewsTasksDataSource(
private val workManager: WorkManager
) {
fun fetchNewsPeriodically() {
val fetchNewsRequest = PeriodicWorkRequestBuilder<RefreshLatestNewsWorker>(
REFRESH_RATE_HOURS, TimeUnit.HOURS
).setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.TEMPORARILY_UNMETERED)
.setRequiresCharging(true)
.build()
)
.addTag(TAG_FETCH_LATEST_NEWS)
workManager.enqueueUniquePeriodicWork(
FETCH_LATEST_NEWS_TASK,
ExistingPeriodicWorkPolicy.KEEP,
fetchNewsRequest.build()
)
}
fun cancelFetchingNewsPeriodically() {
workManager.cancelAllWorkByTag(TAG_FETCH_LATEST_NEWS)
}
}
Bu tür sınıflara, sorumlu oldukları verilerden
örneğin, NewsTasksDataSource
veya PaymentsTasksDataSource
. Tüm görevlerle ilgili
aynı sınıf içine alınmalıdır.
Görevin uygulama başlatılırken tetiklenmesi gerekiyorsa
Uygulama Başlatma aracılığıyla WorkManager isteği
kod deposunu
Initializer
.
WorkManager API'leriyle çalışma hakkında daha fazla bilgi için bkz. WorkManager kılavuzlar.
Test
Bağımlılık yerleştirme ile ilgili en iyi uygulamalar, en iyi uygulamaları paylaşacağız. Kullanışlı bir ortama sahip sınıflarda dış kaynaklarla iletişim kurmanız gerekir. Bir birimi test ederken sahte testi deterministik ve güvenilir kılmak için bağımlılıklarının farklı versiyonlarını sunar.
Birim testleri
Veriler test edilirken genel test kılavuzu geçerlidir. katmanıdır. Birim testleri için gerektiğinde gerçek nesneler kullanın ve bağımlılıkları taklit edin bir dosyadan okuma veya bir kaynaktan okuma gibi harici kaynaklara ulaşan ağa katılmaz.
Entegrasyon testleri
Harici kaynaklara erişen entegrasyon testleri daha az deterministiktir çünkü gerçek bir cihazda çalışmaları gerekiyor. Optimum kampanya performansı için kontrollü bir ortamda yürütülen testlerin sayısını artırır. yardımcı olur.
Oda, veritabanları için tam olarak sizin hazırlayabileceğiniz bellek içi veritabanı oluşturmaya olanak tanır. kontrol etmenize yardımcı olur. Daha fazla bilgi edinmek için veritabanı sayfasını ziyaret edin.
Ağ için WireMock veya ÖrnekWebSunucusu HTTP ve HTTPS çağrıları yapmanıza ve isteklerin aşağıdaki şekilde yapıldığını doğrulamanıza olanak tanır: bekleniyor.
Örnekler
Aşağıdaki Google örnekleri, veri katmanının kullanımını göstermektedir. Uygulamadaki bu rehberliği görmek için bu yöntemleri inceleyin:
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Alan katmanı
- Çevrimdışına öncelik veren bir uygulama geliştirme
- Kullanıcı arayüzü durumu üretimi