রুম 2.x থেকে রুম 3.0-এ স্থানান্তরিত করুন

রুম ৩.০ হলো একটি প্রধান সংস্করণ আপডেট যা লাইব্রেরিটিকে কোটলিন-ফার্স্ট করে তুলেছে। এটি কোটলিন মাল্টিপ্ল্যাটফর্ম (কেএমপি) সমর্থন করে, কোটলিন সিম্বল প্রসেসিং (কেএসপি) আবশ্যক করে এবং অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য কো-রুটিন ব্যবহার বাধ্যতামূলক করে।

বিদ্যমান Room 2.x অ্যাপ এবং ট্রানজিটিভ ডিপেন্ডেন্সিগুলোর সাথে সামঞ্জস্যের সমস্যা এড়ানোর জন্য, Room 3.0 একটি নতুন প্যাকেজে রাখা হয়েছে: androidx.room3

এই নির্দেশিকায় আপনার বিদ্যমান Room 2.x বাস্তবায়নকে Room 3.0-এ স্থানান্তরিত করার জন্য প্রয়োজনীয় পদক্ষেপগুলো বর্ণনা করা হয়েছে।

রুম ৩.০-এর প্রধান পরিবর্তনসমূহ

মাইগ্রেশন শুরু করার আগে, প্রধান পার্থক্যগুলো জেনে নিন:

  • নতুন প্যাকেজ ও আর্টিফ্যাক্ট : সমস্ত ক্লাস androidx.room3 এ থাকে। আর্টিফ্যাক্টগুলো room3 প্রিফিক্স ব্যবহার করে, যেমন androidx.room3:room3-runtime
  • শুধুমাত্র কোটলিন এবং KSP : Room 3.0 জাভা কোড জেনারেশন সমর্থন করে না। KAPT বা জাভা অ্যানোটেশন প্রসেসরের পরিবর্তে KSP ব্যবহার করুন। Room 3.0 এখনও ইনপুট হিসেবে জাভা সোর্স সমর্থন করে।
  • প্রথমে কোরাউটিন : অবজার্ভেবল টাইপ ছাড়া, ডিএও (DAO) ফাংশনগুলোকে অবশ্যই suspend ফাংশন হতে হবে। CoroutineContext এক্সিকিউটরের স্থান নেয়।
  • SupportSQLite নেই : Room-এ SQLiteDriver API ফিরে এসেছে। Room তার কোর API থেকে SupportSQLiteDatabase সরিয়ে দিয়েছে।
  • এপিআই পরিবর্তন : মাইগ্রেশন এবং ডাটাবেস কলব্যাকে SupportSQLiteDatabase এর পরিবর্তে SQLiteConnection ব্যবহৃত হয়।
  • রিঅ্যাক্টিভ টাইপের কনভার্টার: RxJava, LiveData, Guava, এবং Paging রিটার্ন টাইপের জন্য আপনাকে @DaoReturnTypeConverters রেজিস্টার করতে হবে।

আমরা দুটি স্বতন্ত্র ধাপে মাইগ্রেট করার পরামর্শ দিই: প্রথমে Room 2.x-এ আপনার কোডবেস প্রস্তুত ও আধুনিকীকরণ করা, এবং তারপর Room 3.0-এ স্থানান্তরিত হওয়া।


রুম ২.x প্রস্তুত ও আধুনিকীকরণ করুন।

Room 3.0-এ স্থানান্তরিত হওয়ার আগে, আপনি Room 2.8-এর মতো বর্তমান Room 2.x রিলিজে আপডেট করার মাধ্যমে বেশিরভাগ আধুনিকীকরণের কাজ সম্পন্ন করতে পারেন। Room 2.8 কোটলিন মাল্টিপ্ল্যাটফর্ম বা KMP সমর্থন করে এবং এতে Room 3.0-এর ব্যবহৃত অনেক ড্রাইভার API অন্তর্ভুক্ত রয়েছে।

রুম ২.৮ এবং উচ্চতর রুমে আপগ্রেড করুন।

বর্তমান Room 2.x রিলিজটি ব্যবহার করার জন্য আপনার বিল্ড কনফিগারেশন আপডেট করুন:

[versions]
room2 = "2.8.4" # Use the current Room 2.8 version

[libraries]
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room2" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room2" }

KAPT থেকে KSP-তে মাইগ্রেট করুন

রুম ৩.০ জাভা অ্যানোটেশন প্রসেসর বা KAPT সমর্থন করে না। আপনাকে অবশ্যই কোটলিন সিম্বল প্রসেসিং (KSP) ব্যবহার করতে হবে। আপনি রুম ২.x-এ থাকা অবস্থাতেই এই পরিবর্তনটি করতে পারেন।

  1. আপনার মডিউলের build.gradle.kts ফাইলে KSP প্লাগইনটি প্রয়োগ করুন:

    plugins {
        id("com.google.devtools.ksp") version "<ksp_version>"
    }
    

    নিশ্চিত করুন যে KSP সংস্করণটি আপনার Kotlin সংস্করণের সাথে সামঞ্জস্যপূর্ণ।

  2. Room কম্পাইলার নির্ভরতার জন্য kapt বা annotationProcessor পরিবর্তে ksp ব্যবহার করুন:

    dependencies {
        implementation(libs.androidx.room.runtime)
        ksp(libs.androidx.room.compiler)
    }
    

কো-রুটিন গ্রহণ করুন

রুম ৩.০-তে অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য কো-রুটিন প্রয়োজন।

  • আপনার DAO-গুলো আপডেট করুন: যদি না তারা Flow বা RxJava টাইপের মতো কোনো অবজার্ভেবল রিঅ্যাক্টিভ টাইপ রিটার্ন করে, তাহলে সমস্ত DAO ফাংশন অবশ্যই suspend ফাংশন হতে হবে।
// Before (Blocking)
@Dao
interface UserDao {
    @Query("SELECT * FROM User")
    fun getAll(): List<User>
}

// After (Suspend)
@Dao
interface UserDao {
    @Query("SELECT * FROM User")
    suspend fun getAll(): List<User>
}
  • যদি আপনি ডাটাবেস অপারেশন সম্পাদনের জন্য একটি কাস্টম Executor দিয়ে আপনার RoomDatabase কনফিগার করে থাকেন, তাহলে বিল্ডারে setQueryCoroutineContext ব্যবহার করে CoroutineContext এ মাইগ্রেট করুন:
Room.databaseBuilder<AppDatabase>(context, "db")
    .setQueryCoroutineContext(Dispatchers.IO)
    .build()

ড্রাইভার এপিআই গ্রহণ করুন এবং SQLite সমর্থন পরিহার করুন।

Room 3.0 সম্পূর্ণরূপে SQLiteDriver দ্বারা সমর্থিত এবং এর কোর API-গুলোতে আর SupportSQLiteDatabase সমর্থন করে না।

আপনার ডাটাবেস বিল্ডারে SQLiteDriver সেট করার জন্য যদি আপনি setDriver কল না করেন, তাহলে Room 2.8 একটি কম্প্যাটিবিলিটি মোডে কাজ করে যেখানে Support SQLite এবং Driver API উভয়ই সক্রিয় থাকে। এই কম্প্যাটিবিলিটি মোড আপনাকে ড্রাইভারটি সক্রিয় করার আগে পর্যায়ক্রমে আপনার কোডবেস রূপান্তর করার সুযোগ দেয়।

  • মাইগ্রেশন রূপান্তর করুন : আপনার Migration এবং AutoMigrationSpec সাবক্লাসগুলিকে SupportSQLiteDatabase এর পরিবর্তে SQLiteConnection ব্যবহার করার জন্য মাইগ্রেট করুন।
// Before (SupportSQLiteDatabase)
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL("ALTER TABLE User ADD COLUMN age INTEGER DEFAULT 0 NOT NULL")
    }
}

// After (SQLiteConnection - Room 2.8)
import androidx.sqlite.SQLiteConnection
import androidx.sqlite.execSQL

val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(connection: SQLiteConnection) {
        connection.execSQL(
            "ALTER TABLE User ADD COLUMN age INTEGER DEFAULT 0 NOT NULL"
        )
    }
}
  • ডাটাবেস কলব্যাক রূপান্তর করুন : SQLiteConnection ব্যবহার করার জন্য RoomDatabase.Callback ইমপ্লিমেন্টেশন আপডেট করুন :
// Before (SupportSQLiteDatabase)
val callback = object : RoomDatabase.Callback() {
    override fun onCreate(db: SupportSQLiteDatabase) {
        // ...
    }
}

// After (SQLiteConnection - Room 2.8)
val callback = object : RoomDatabase.Callback() {
    override fun onCreate(connection: SQLiteConnection) {
        // ...
    }
}
  • @RawQuery DAO ফাংশন রূপান্তর করুন : @RawQuery টীকাযুক্ত ফাংশনগুলির জন্য, SupportSQLiteQuery এর পরিবর্তে RoomRawQuery ব্যবহার করুন:
// Before (SupportSQLiteQuery)
@Dao
interface UserDao {
    @RawQuery
    fun getUser(query: SupportSQLiteQuery): User
}

// After (RoomRawQuery)
@Dao
interface UserDao {
    @RawQuery
    suspend fun getUser(query: RoomRawQuery): User
}

আপনি রানটাইমে একটি RoomRawQuery তৈরি করতে পারেন:

val query = RoomRawQuery(
    sql = "SELECT * FROM User WHERE id = ?",
    onBindStatement = { statement ->
        statement.bindInt(1, userId)
    }
)
  • ট্রানজ্যাকশন এপিআই রূপান্তর করুন : শুধুমাত্র অ্যান্ড্রয়েডের জন্য withTransaction এবং runInTransaction ব্লকগুলোকে withWriteTransaction অথবা withReadTransaction দিয়ে প্রতিস্থাপন করুন :
// Before (withTransaction)
db.withTransaction {
    // perform database operations
}

// After (withWriteTransaction - Room 2.8)
import androidx.room.withWriteTransaction

db.withWriteTransaction {
    // perform database operations
}

যদি আপনার ট্রানজ্যাকশন কানেকশনে সরাসরি নিম্ন-স্তরের অ্যাক্সেসের প্রয়োজন হয়, তাহলে আপনি immediateTransaction এর সাথে useWriterConnection ও ব্যবহার করতে পারেন।

  • SupportSQLiteDatabase এর সরাসরি ব্যবহার পরিহার করুন : যদি আপনার এমন ব্যাপক লিগ্যাসি কোড থাকে যার জন্য এখনও SupportSQLiteDatabase প্রয়োজন এবং আপনি এখনও তা মাইগ্রেট করতে পারছেন না, androidx.room:room-sqlite-wrapper কম্প্যাটিবিলিটি আর্টিফ্যাক্টটি ব্যবহার করুন:
dependencies {
    implementation("androidx.room:room-sqlite-wrapper:$roomVersion")
}

এবং তারপরে, আপনার Room ডাটাবেস ইনস্ট্যান্স থেকে একটি SupportSQLiteDatabase পেতে getSupportWrapper ব্যবহার করুন:

import androidx.room.support.getSupportWrapper

val legacyDb: SupportSQLiteDatabase = roomDatabase.getSupportWrapper()
  • SQLite ড্রাইভার সেট করুন : সমস্ত Room API ব্যবহার ড্রাইভার API-তে স্থানান্তরিত করার পরে, আপনার RoomDatabase বিল্ডারে setDriver কল করে BundledSQLiteDriver বা AndroidSQLiteDriver মতো একটি ড্রাইভার কনফিগার করুন:
import androidx.sqlite.driver.bundled.BundledSQLiteDriver

val db = Room.databaseBuilder<AppDatabase>(context, "db")
    .setDriver(BundledSQLiteDriver())
    .build()

প্রবাহ-ভিত্তিক অবৈধকরণ ট্র্যাকিং গ্রহণ করুন

রুম ২.৮-এ InvalidationTracker.createFlow API চালু করা হয়েছে। রুম ২.x ব্যবহার করার সময় পুরোনো InvalidationTracker.Observer ইমপ্লিমেন্টেশন থেকে সরে আসতে এই API-টি ব্যবহার করুন। এটি আপনার কোডবেসকে রুম ৩.০-এর জন্য প্রস্তুত করে, যা Observer সম্পূর্ণরূপে সরিয়ে দেয়।

// Before (InvalidationTracker.Observer)
val observer = object : InvalidationTracker.Observer("User") {
    override fun onInvalidated(tables: Set<String>) {
        // reload user data
    }
}
db.invalidationTracker.addObserver(observer)

// After (createFlow - Room 2.8)
val userFlow = db.invalidationTracker.createFlow("User").map { _ ->
    userDao.getAllUsers()
}

রুম ৩.০-এ স্থানান্তরিত হন

একবার আপনি Room 2.x-এ আপনার অ্যাপ্লিকেশনটি আধুনিকীকরণ করলে, Room 3.0-এ স্থানান্তরের জন্য ডিপেন্ডেন্সি, প্যাকেজ ইম্পোর্ট এবং ডাটাবেস কলব্যাক আপডেট করতে হয়।

নির্ভরতা এবং প্যাকেজ আমদানি আপডেট করুন

  • আপনার বিল্ড কনফিগারেশনে, androidx.room ডিপেন্ডেন্সিগুলো androidx.room3 দিয়ে প্রতিস্থাপন করুন:
[versions]
room3 = "3.0.0" # Use the current Room 3.0 version

[libraries]
androidx-room3-runtime = { module = "androidx.room3:room3-runtime", version.ref = "room3" }
androidx-room3-compiler = { module = "androidx.room3:room3-compiler", version.ref = "room3" }
  • আপনার নির্ভরতা ব্লকটি আপডেট করুন:
dependencies {
    implementation(libs.androidx.room3.runtime)
    ksp(libs.androidx.room3.compiler)
}
  • আপনার প্যাকেজ ইম্পোর্টগুলো আপডেট করুন। import androidx.room.* এর পরিবর্তে import androidx.room3.* ব্যবহার করুন।

টাইপ কনভার্টার এপিআই আপডেট করুন

রুম ৩.০ কলামের মান রূপান্তরের ক্ষেত্রে টাইপ কনভার্টার এপিআইগুলোর ব্যবহার স্পষ্ট করার জন্য এবং ডিএও (DAO) রিটার্ন টাইপ কনভার্টারগুলোর সাথে বিভ্রান্তি এড়ানোর জন্য সেগুলোর নাম পরিবর্তন করেছে।

আপনার কোডবেসে নিম্নলিখিত অ্যানোটেশন এবং ফাংশনগুলো আপডেট করুন:

  • @TypeConverter @ColumnTypeConverter এ রিনেম করুন।
  • @TypeConverters @ColumnTypeConverters এ রিনেম করুন।
  • @ProvidedTypeConverter @ProvidedColumnTypeConverter এ রিনেম করুন।
  • RoomDatabase.Builder.addTypeConverter কে addColumnTypeConverter এ রিনেম করুন।

উদাহরণ:

// Before
@ProvidedTypeConverter
class Converters {
  @TypeConverter
  fun fromTimestamp(value: Long?): Date? = ...
}

@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase()

val db = Room.databaseBuilder<AppDatabase>(...)
  .addTypeConverter(convertersInstance)
  .build()
// After
import androidx.room3.ColumnTypeConverter
import androidx.room3.ColumnTypeConverters
import androidx.room3.ProvidedColumnTypeConverter

@ProvidedColumnTypeConverter
class Converters {
  @ColumnTypeConverter
  fun fromTimestamp(value: Long?): Date? = ...
}

@Database(entities = [User::class], version = 1)
@ColumnTypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase()

val db = Room.databaseBuilder<AppDatabase>(...)
  .addColumnTypeConverter(convertersInstance)
  .build()

ফাংশন স্থগিত করতে কলব্যাকগুলি আপডেট করুন

রুম ৩.০-তে, ডাটাবেস কলব্যাক এবং মাইগ্রেশনগুলো SQLiteConnection ব্যবহার করে এবং এগুলো suspend ফাংশন।

  • আপনার ম্যানুয়াল Migration ক্লাসগুলো আপডেট করুন:
import androidx.sqlite.SQLiteConnection
import androidx.sqlite.async.executeSQL

val MIGRATION_1_2 = object : Migration(1, 2) {
    override suspend fun migrate(connection: SQLiteConnection) {
        connection.executeSQL(
            "ALTER TABLE User ADD COLUMN age INTEGER DEFAULT 0 NOT NULL"
        )
    }
}
  • আপনার RoomDatabase.Callback ইমপ্লিমেন্টেশনগুলো আপডেট করুন:
val callback = object : RoomDatabase.Callback() {
    override suspend fun onCreate(connection: SQLiteConnection) {
        // ...
    }
}

DAO রিটার্ন টাইপ কনভার্টার নিবন্ধন করুন

রুম ৩.০-তে, RxJava, LiveData, Guava, এবং Paging-এর মতো রিঅ্যাক্টিভ রিটার্ন টাইপগুলোর জন্য আপনাকে @DaoReturnTypeConverters ব্যবহার করে DAO রিটার্ন টাইপ কনভার্টার রেজিস্টার করতে হবে।

import androidx.room3.paging.PagingSourceDaoReturnTypeConverter

@Dao
@DaoReturnTypeConverters(PagingSourceDaoReturnTypeConverter::class)
interface UserDao {
    @Query("SELECT * FROM User")
    fun getAllPaginated(): PagingSource<Int, User>
}
  • পেজিং ( PagingSource ) : androidx.room3:room3-paging আর্টিফ্যাক্ট থেকে PagingSourceDaoReturnTypeConverter রেজিস্টার করুন।
  • RxJava ( Observable , Flowable , Single , Maybe , Completable ) : androidx.room3:room3-rxjava3 আর্টিফ্যাক্ট থেকে RxDaoReturnTypeConverters রেজিস্টার করুন।
  • Guava ( ListenableFuture ) : androidx.room3:room3-guava আর্টিফ্যাক্ট থেকে GuavaDaoReturnTypeConverter রেজিস্টার করুন।
  • LiveData ( LiveData ) : androidx.room3:room3-livedata আর্টিফ্যাক্ট থেকে LiveDataDaoReturnTypeConverter রেজিস্টার করুন।

ইনভ্যালিডেশনট্র্যাকার পর্যবেক্ষক অপসারণ যাচাই করুন

রুম ৩.০ সম্পূর্ণরূপে InvalidationTracker.Observer এবং এর সাথে সম্পর্কিত রেজিস্ট্রেশন মেথডগুলো, যেমন addObserverremoveObserver , সরিয়ে দেয়।

যদি আপনি প্রথম পর্যায়েই কো-রুটিন ফ্লো-তে স্থানান্তরিত না হয়ে থাকেন, তবে আপনাকে অবশ্যই Observer সমস্ত ব্যবহার createFlow তে মাইগ্রেট করতে হবে:

val userFlow = db.invalidationTracker.createFlow("User").map { _ ->
    userDao.getAllUsers()
}