Veri katmanı

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.

Tipik bir mimaride, veri katmanının depoları veri sağlamak
    uygulamanın geri kalanında yayınlanır ve
veri kaynaklarına bağlıdır.
Şekil 1. Uygulama mimarisindeki veri katmanının rolü.

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ını (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 veya Completable 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 veya Flowable 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.

Örnekte, UserRepository diğer iki depo sınıfına bağlıdır:
    Diğer giriş veri kaynaklarına bağlı olan LoginRepository (Giriş Deposu); ve
    RegistrationRepository (Diğer kayıt veri kaynaklarına bağlı)
Şekil 2. Diğerlerine bağımlı olan bir deponun bağımlılık grafiği ekleyebilirsiniz.

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 ve edinmeniz gereken bağımlılıkları ifade eder. 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 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 sayfadaki ArticleApiModel bölümünü kırparak 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.CoroutineDispatcherExecutor

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ı biçimlerde olabilir. Basit bir değişkenden farklı olabilir, değişkenini okuma/yazma işlemlerinden koruyan daha karmaşık bir sınıfa dönüştürür. 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ğ.

Entegrasyon testleri

Harici kaynaklara erişen entegrasyon testleri daha az deterministiktir çünkü gerçek bir cihazda çalışmaları gerekiyor. Optimum kampanya performansı için entegrasyon testlerinin daha verimli hale gelmesini sağlamak için 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: