एसिंक्रोनस डीएओ क्वेरी लिखें

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

डीएओ क्वेरी को तीन कैटगरी में बांटा गया है:

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

भाषा और फ़्रेमवर्क के विकल्प

Room, खास लैंग्वेज फ़ीचर और लाइब्रेरी के साथ इंटरऑपरेबिलिटी के लिए इंटिग्रेशन की सुविधा देता है. यहां दी गई टेबल में, क्वेरी टाइप और फ़्रेमवर्क के हिसाब से लागू होने वाले रिटर्न टाइप दिखाए गए हैं:

क्वेरी का टाइप Kotlin लैंग्वेज के फ़ीचर (नेटिव) RxJava ग्वावा Jetpack Lifecycle*
वन-शॉट राइट कोरूटीन (suspend) Single<T>, Maybe<T>, Completable ListenableFuture<T> लागू नहीं
वन-शॉट रीड कोरूटीन (suspend) Single<T>, Maybe<T> ListenableFuture<T> लागू नहीं
ऑब्ज़र्वेबल रीड Flow<T> Flowable<T>, Publisher<T>, Observable<T> लागू नहीं LiveData<T>

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

Flow और कोरूटीन के साथ Kotlin

Kotlin में, ऐसी बिल्ट-इन लैंग्वेज सुविधाएं मौजूद हैं जिनकी मदद से, तीसरे पक्ष के फ़्रेमवर्क के बिना एसिंक्रोनस क्वेरी लिखी जा सकती हैं:

  • Room, ऑब्ज़र्वेबल क्वेरी लिखने के लिए, Kotlin के Flow साथ सीधे तौर पर काम करता है.
  • Room को suspend कीवर्ड की ज़रूरत होती है, ताकि डीएओ की वन-शॉट क्वेरी को Kotlin कोरूटीन के साथ एसिंक्रोनस बनाया जा सके.

कोरूटीन और Flow की सुविधा, Room के कोर रनटाइम में सीधे तौर पर शामिल होती है. इसलिए, किसी अतिरिक्त आर्टफ़ैक्ट की ज़रूरत नहीं होती.

Kotlin और Java के लिए RxJava

Room 3.0, RxJava 3 के रिटर्न टाइप के साथ काम करता है. RxJava के रिटर्न टाइप का इस्तेमाल करने के लिए, आपको अपने डेटाबेस या डीएओ में, RxJava के रिटर्न टाइप के कन्वर्टर रजिस्टर करने होंगे:

  1. अपने बिल्ड कॉन्फ़िगरेशन में, androidx.room3:room3-rxjava3 आर्टफ़ैक्ट शामिल करें.
  2. अपने @Database या @Dao के एलान में @DaoReturnTypeConverters(RxDaoReturnTypeConverters::class) एनोटेशन जोड़ें.

Room, RxJava 3 के इन रिटर्न टाइप के साथ काम करता है:

LiveData और ग्वावा

Room 3.0, कन्वर्टर का इस्तेमाल करके, LiveData और Guava के ListenableFuture रिटर्न टाइप के साथ काम करता है:

  • LiveData: androidx.room3:room3-livedata आर्टफ़ैक्ट शामिल करें और अपने डेटाबेस या डीएओ में @DaoReturnTypeConverters(LiveDataDaoReturnTypeConverter::class) एनोटेशन जोड़ें.
  • ग्वावा: androidx.room3:room3-guava आर्टफ़ैक्ट शामिल करें और अपने डेटाबेस या डीएओ में @DaoReturnTypeConverters(GuavaDaoReturnTypeConverter::class) एनोटेशन जोड़ें.

एसिंक्रोनस वन-शॉट क्वेरी लिखना

वन-शॉट क्वेरी, डेटाबेस की ऐसी कार्रवाइयां होती हैं जो सिर्फ़ एक बार चलती हैं और एक्ज़ीक्यूशन के समय डेटा का स्नैपशॉट लेती हैं. यहां एसिंक्रोनस वन-शॉट क्वेरी के कुछ उदाहरण दिए गए हैं:

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    suspend fun loadUserById(id: Int): User

    @Query("SELECT * from user WHERE region IN (:regions)")
    suspend fun loadUsersByRegion(regions: List<String>): List<User>
}

ऑब्ज़र्वेबल क्वेरी लिखना

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

@Dao
interface ObservableUserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    fun loadUserById(id: Int): Flow<User>

    @Query("SELECT * from user WHERE region IN (:regions)")
    fun loadUsersByRegion(regions: List<String>): Flow<List<User>>
}

डेटाबेस के अमान्य होने की जानकारी मैन्युअल तरीके से ट्रैक करना

ऑब्ज़र्वेबल डेटाबेस ऑपरेशन को मैन्युअल तरीके से बनाने के लिए, InvalidationTracker के createFlow एपीआई का इस्तेमाल किया जा सकता है. इस एपीआई की मदद से, ऐसा Flow बनाया जा सकता है जो खास टेबल में किए गए बदलावों को ट्रैक करता है. साथ ही, उन टेबल में बदलाव होने पर सूचना जनरेट करता है.

fun getArtistTours(db: RoomDatabase, from: Date, to: Date): Flow<Map<Artist, TourState>> {
    return db.invalidationTracker.createFlow("Artist").map { _ ->
        val artists = artistsDao.getAllArtists()
        val tours = tourService.fetchStates(artists.map { it.id })
        associateTours(artists, tours, from, to)
    }
}

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

डीएओ रिटर्न टाइप के कस्टम कन्वर्टर

ऐसे टाइप के लिए जो Room या उसकी एक्सटेंशन लाइब्रेरी के साथ सीधे तौर पर काम नहीं करते, डीएओ रिटर्न टाइप के कस्टम कन्वर्टर तय किए जा सकते हैं. इससे, रिटर्न टाइप की अतिरिक्त सुविधाओं का इस्तेमाल किया जा सकता है. डीएओ फ़ंक्शन के नतीजे को अपने कस्टम टाइप में बदलने के लिए, कन्वर्टर फ़ंक्शन में @DaoReturnTypeConverter एनोटेशन जोड़ें.

उदाहरण के लिए, ऐसा कन्वर्टर तय किया जा सकता है जो क्वेरी के एक्ज़ीक्यूशन के आस-पास ट्रेस सेक्शन जोड़ने के लिए, androidx.tracing का इस्तेमाल करता है. इससे, परफ़ॉर्मेंस के हिसाब से अहम क्वेरी की निगरानी की जा सकती है. इसके लिए, एक्ज़ीक्यूशन को TracedQuery के कस्टम टाइप में रैप करें:

class TracedQuery<T>(val result: T)

object TracingDaoReturnTypeConverter {
    @DaoReturnTypeConverter([OperationType.READ])
    suspend fun <T> convert(
        rawQuery: RoomRawQuery,
        executeAndConvert: suspend () -> T
    ): TracedQuery<T> {
        val result = trace("TracedQuery: ${rawQuery.sql}") {
            executeAndConvert()
        }
        return TracedQuery(result)
    }
}

कन्वर्टर का इस्तेमाल करने के लिए, अपने डेटाबेस या डीएओ में @DaoReturnTypeConverters एनोटेशन जोड़ें:

@Dao
@DaoReturnTypeConverters(TracingDaoReturnTypeConverter::class)
interface MusicDao {
    @Query("SELECT * FROM Song")
    suspend fun getAllSongs(): TracedQuery<List<Song>>
}

डीएओ रिटर्न टाइप के कन्वर्टर के शुरू होने की प्रोसेस को कंट्रोल करना

आम तौर पर, Room, डीएओ रिटर्न टाइप के कन्वर्टर के इंस्टैंशिएशन को मैनेज करता है. हालांकि, अगर आपको अपने कन्वर्टर क्लास में अतिरिक्त डिपेंडेंसी पास करनी हैं, तो आपके ऐप्लिकेशन को उनके शुरू होने की प्रोसेस को सीधे तौर पर कंट्रोल करना होगा. ऐसा होने पर, अपने कन्वर्टर क्लास में @ProvidedDaoReturnTypeConverterएनोटेशन जोड़ें:

@ProvidedDaoReturnTypeConverter
class TracingDaoReturnTypeConverter(val tracer: Tracer) {
    @DaoReturnTypeConverter([OperationType.READ])
    suspend fun <T> convert(
        rawQuery: RoomRawQuery,
        executeAndConvert: suspend () -> T
    ): TracedQuery<T> {
        val result = tracer.trace("TracedQuery: ${rawQuery.sql}") {
            executeAndConvert()
        }
        return TracedQuery(result)
    }
}

इसके बाद, @DaoReturnTypeConverters में अपने कन्वर्टर क्लास का एलान करने के अलावा, RoomDatabase.Builder.addDaoReturnTypeConverter फ़ंक्शन का इस्तेमाल करके, अपने कन्वर्टर क्लास का इंस्टेंस, RoomDatabase बिल्डर को पास करें:

val db = Room.databaseBuilder<MyDatabase>(applicationContext, "database-name")
    .addDaoReturnTypeConverter(TracingDaoReturnTypeConverter(myLoggerInstance))
    .build()

कन्वर्टर फ़ंक्शन के लिए ज़रूरी शर्तें

@DaoReturnTypeConverter फ़ंक्शन को कई शर्तों को पूरा करना होगा:

  • इसके आखिरी आर्ग्युमेंट के तौर पर, फ़ंक्शनल पैरामीटर होना चाहिए. इसे आम तौर पर executeAndConvert नाम दिया जाता है. यह पैरामीटर, suspend लैम्डा होता है. इसे Room, क्वेरी को लागू करने और नतीजे को पार्स करने के लिए जनरेट करता है.
    • अगर कन्वर्टर को क्वेरी में बदलाव करना है, जैसे कि पेजिंग, तो लैम्डा, RoomRawQuery पैरामीटर ले सकता है.
  • यह लैम्डा से पहले, इन पैरामीटर को स्वीकार कर सकता है:
    • db: RoomDatabase: इससे डेटाबेस इंस्टेंस को ऐक्सेस किया जा सकता है. यह कोरूटीन स्कोप पाने या अतिरिक्त कार्रवाइयां करने के लिए काम का है.
    • tableNames: Array<String> या List<String>: इससे क्वेरी से ऐक्सेस की गई टेबल के नाम मिलते हैं. यह ऑब्ज़र्वेबल टाइप के लिए काम का है.
    • rawQuery: RoomRawQuery: इससे क्वेरी का रनटाइम इंस्टेंस मिलता है.
    • inTransaction: Boolean: इससे पता चलता है कि क्वेरी, लेन-देन के दौरान लागू हो रही है या नहीं.