অসিঙ্ক্রোনাস DAO প্রশ্ন লিখুন

কোয়েরি যাতে UI ব্লক না করে, সেজন্য Room মেইন থ্রেডে ডাটাবেস অ্যাক্সেস সমর্থন করে না। এই সীমাবদ্ধতার কারণে আপনাকে আপনার DAO কোয়েরিগুলো অ্যাসিঙ্ক্রোনাস করতে হবে। অ্যাসিঙ্ক্রোনাস কোয়েরি এক্সিকিউশন প্রদানের জন্য Room লাইব্রেরিতে বিভিন্ন ফ্রেমওয়ার্কের সাথে ইন্টিগ্রেশন রয়েছে।

DAO কোয়েরিগুলো তিনটি শ্রেণীতে বিভক্ত:

  • এককালীন রাইট কোয়েরি যা ডাটাবেসে ডেটা সন্নিবেশ, আপডেট বা মুছে ফেলে।
  • ওয়ান-শট রিড কোয়েরি হলো এমন কোয়েরি যা আপনার ডাটাবেস থেকে শুধুমাত্র একবার ডেটা রিড করে এবং সেই সময়ের ডাটাবেসের একটি স্ন্যাপশটসহ ফলাফল প্রদান করে।
  • অবজার্ভেবল রিড কোয়েরি, যা ডেটাবেসের টেবিলগুলো পরিবর্তিত হওয়ার সাথে সাথে সেখান থেকে ডেটা রিড করে এবং সেই পরিবর্তনগুলো প্রতিফলিত করার জন্য নতুন ভ্যালু প্রদান করে।

ভাষা এবং ফ্রেমওয়ার্ক বিকল্পগুলি

Room নির্দিষ্ট ভাষার বৈশিষ্ট্য এবং লাইব্রেরির সাথে আন্তঃকার্যক্ষমতার জন্য ইন্টিগ্রেশন সমর্থন প্রদান করে। নিম্নলিখিত সারণিটি কোয়েরির ধরন এবং ফ্রেমওয়ার্কের উপর ভিত্তি করে প্রযোজ্য রিটার্ন টাইপগুলো দেখায়:

কোয়েরি টাইপ কোটলিন ভাষার বৈশিষ্ট্য (নেটিভ) RxJava পেয়ারা জেটপ্যাক জীবনচক্র*
এক শটে লেখা কো-রুটিন ( 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>

এই নির্দেশিকাটি আপনার DAO-গুলিতে অ্যাসিঙ্ক্রোনাস কোয়েরি বাস্তবায়নের জন্য এই ইন্টিগ্রেশনগুলি ব্যবহার করার তিনটি উপায় প্রদর্শন করে।

ফ্লো এবং কোরাউটিন সহ কোটলিন

কোটলিনে এমন কিছু বিল্ট-ইন ল্যাঙ্গুয়েজ ফিচার রয়েছে যা আপনাকে কোনো থার্ড-পার্টি ফ্রেমওয়ার্ক ছাড়াই অ্যাসিঙ্ক্রোনাস কোয়েরি লিখতে দেয়:

  • অবজার্ভেবল কোয়েরি লেখার জন্য Room সরাসরি Kotlin-এর Flow সমর্থন করে।
  • Kotlin coroutine ব্যবহার করে আপনার ওয়ান-শট DAO কোয়েরিগুলোকে অ্যাসিঙ্ক্রোনাস করার জন্য Room-এ suspend কীওয়ার্ডটি প্রয়োজন হয়।

কোর রুম রানটাইমের মধ্যেই সরাসরি কো-রুটিন এবং ফ্লো সাপোর্ট অন্তর্ভুক্ত করা আছে, তাই কোনো অতিরিক্ত উপকরণের প্রয়োজন নেই।

কোটলিন এবং জাভার জন্য RxJava

রুম ৩.০ আরএক্সজাভা ৩ রিটার্ন টাইপ সমর্থন করে। আরএক্সজাভা রিটার্ন টাইপ ব্যবহার করতে হলে, আপনাকে আপনার ডাটাবেস বা ডিএও-তে আরএক্সজাভা রিটার্ন টাইপ কনভার্টারগুলো রেজিস্টার করতে হবে:

  1. আপনার বিল্ড কনফিগারেশনে androidx.room3:room3-rxjava3 আর্টিফ্যাক্টটি অন্তর্ভুক্ত করুন।
  2. আপনার @Database অথবা @Dao ডিক্লারেশনকে @DaoReturnTypeConverters(RxDaoReturnTypeConverters::class) দিয়ে টীকাযুক্ত করুন।

Room নিম্নলিখিত RxJava 3 রিটার্ন টাইপগুলো সমর্থন করে:

লাইভডেটা এবং গুয়াভা

Room 3.0 কনভার্টার ব্যবহার করে LiveData এবং Guava ListenableFuture রিটার্ন টাইপ সমর্থন করে:

  • LiveData : androidx.room3:room3-livedata আর্টিফ্যাক্টটি অন্তর্ভুক্ত করুন এবং আপনার ডাটাবেস বা DAO-কে @DaoReturnTypeConverters(LiveDataDaoReturnTypeConverter::class) দিয়ে অ্যানোটেট করুন।
  • গুয়াভা : androidx.room3:room3-guava আর্টিফ্যাক্টটি অন্তর্ভুক্ত করুন এবং আপনার ডাটাবেস বা DAO-কে @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 API ব্যবহার করতে পারেন। এই API-টি আপনাকে এমন একটি 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 বা এর এক্সটেনশন লাইব্রেরি দ্বারা সরাসরি সমর্থিত নয়, সেগুলোর জন্য আপনি অতিরিক্ত রিটার্ন টাইপ সমর্থন করতে কাস্টম DAO রিটার্ন টাইপ কনভার্টার সংজ্ঞায়িত করতে পারেন। একটি DAO ফাংশনের ফলাফলকে আপনার কাস্টম টাইপে রূপান্তর করতে, কনভার্টার ফাংশনটিকে @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)
    }
}

কনভার্টারটি ব্যবহার করতে, আপনার ডাটাবেস বা DAO-কে @DaoReturnTypeConverters দিয়ে টীকাযুক্ত করুন:

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

কন্ট্রোল ডিএও রিটার্ন টাইপ কনভার্টার প্রারম্ভিকীকরণ

সাধারণত, Room নিজেই DAO রিটার্ন টাইপ কনভার্টারগুলোর ইনস্ট্যানসিয়েশন পরিচালনা করে। তবে, যদি আপনাকে আপনার কনভার্টার ক্লাসগুলোতে অতিরিক্ত ডিপেন্ডেন্সি পাস করতেই হয়, তাহলে আপনার অ্যাপকে অবশ্যই সরাসরি সেগুলোর ইনিশিয়ালাইজেশন নিয়ন্ত্রণ করতে হবে। সেক্ষেত্রে, আপনার কনভার্টার ক্লাসটিকে @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 বিল্ডারে আপনার কনভার্টার ক্লাসের একটি ইনস্ট্যান্স পাস করার জন্য RoomDatabase.Builder.addDaoReturnTypeConverter ফাংশনটি ব্যবহার করুন:

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

রূপান্তরকারী ফাংশনের প্রয়োজনীয়তা

একটি @DaoReturnTypeConverter ফাংশনকে বেশ কিছু শর্ত পূরণ করতে হবে:

  • এর শেষ আর্গুমেন্ট হিসেবে অবশ্যই একটি ফাংশনাল প্যারামিটার থাকতে হবে, যার নাম সাধারণত executeAndConvert । এই প্যারামিটারটি একটি suspend ল্যাম্বডা, যা Room কোয়েরিটি এক্সিকিউট করতে এবং ফলাফলটি পার্স করতে তৈরি করে।
    • যদি কনভার্টারটিকে কোয়েরি রূপান্তর করার প্রয়োজন হয়, যেমন পেজিং-এর ক্ষেত্রে, ল্যাম্বডাটি একটি RoomRawQuery প্যারামিটার নিতে পারে।
  • এটি ঐচ্ছিকভাবে ল্যাম্বডার আগে নিম্নলিখিত প্যারামিটারগুলো গ্রহণ করতে পারে:
    • db: RoomDatabase : ডাটাবেস ইনস্ট্যান্স অ্যাক্সেস করে, যা কো-রুটিন স্কোপ পেতে বা অতিরিক্ত অপারেশন সম্পাদন করতে উপযোগী।
    • tableNames: Array<String> or List<String> : কোয়েরি দ্বারা অ্যাক্সেস করা টেবিলগুলোর নাম প্রদান করে, যা অবজার্ভেবল টাইপের জন্য উপযোগী।
    • rawQuery: RoomRawQuery : কোয়েরিটির রানটাইম ইনস্ট্যান্স প্রদান করে।
    • inTransaction: Boolean : কোয়েরিটি কোনো ট্রানজ্যাকশনের মধ্যে সম্পাদিত হচ্ছে কিনা তা নির্দেশ করে।