কোটলিন মাল্টিপ্ল্যাটফর্মে রুম স্থানান্তর করুন

কোটলিন মাল্টিপ্ল্যাটফর্ম (KMP) ব্যবহার করে একটি বিদ্যমান রুম ইমপ্লিমেন্টেশনকে কীভাবে স্থানান্তর করা যায় তা এই নথিতে বর্ণনা করা হয়েছে।

একটি বিদ্যমান অ্যান্ড্রয়েড কোডবেসে রুম ব্যবহারগুলিকে একটি সাধারণ ভাগ করা KMP মডিউলে স্থানান্তরিত করা রুম API ব্যবহার করা বা কোডবেস ইতিমধ্যেই Coroutines ব্যবহার করলে তার উপর নির্ভর করে অসুবিধার মধ্যে ব্যাপকভাবে পরিবর্তিত হতে পারে। একটি সাধারণ মডিউলে রুমের ব্যবহার স্থানান্তর করার চেষ্টা করার সময় এই বিভাগটি কিছু নির্দেশিকা এবং টিপস দেয়।

রুম এর অ্যান্ড্রয়েড সংস্করণ এবং সেটআপের সাথে জড়িত KMP সংস্করণের মধ্যে পার্থক্য এবং অনুপস্থিত বৈশিষ্ট্যগুলির সাথে প্রথমে নিজেকে পরিচিত করা গুরুত্বপূর্ণ৷ সারমর্মে, একটি সফল মাইগ্রেশনের সাথে SupportSQLite* এপিআই-এর রিফ্যাক্টরিং ব্যবহার এবং SQLite ড্রাইভার এপিআই-এর সাথে রুম ডিক্লেয়ারেশন ( @Database অ্যানোটেটেড ক্লাস, ডিএও, এন্টিটি, ইত্যাদি) সাধারণ কোডে প্রতিস্থাপন করা জড়িত।

চালিয়ে যাওয়ার আগে নিম্নলিখিত তথ্যগুলি পুনরায় দেখুন:

পরবর্তী বিভাগগুলি একটি সফল মাইগ্রেশনের জন্য প্রয়োজনীয় বিভিন্ন পদক্ষেপের বর্ণনা দেয়।

Support SQLite থেকে SQLite Driver-এ স্থানান্তর করুন

androidx.sqlite.db এর APIগুলি শুধুমাত্র Android-এর জন্য, এবং যেকোনো ব্যবহারকে SQLite Driver API-এর সাথে রিফ্যাক্টর করতে হবে। পিছনের দিকে সামঞ্জস্যের জন্য, এবং যতক্ষণ পর্যন্ত RoomDatabase একটি SupportSQLiteOpenHelper.Factory দিয়ে কনফিগার করা হয় (অর্থাৎ কোন SQLiteDriver সেট করা নেই), তখন রুম 'কম্প্যাটিবিলিটি মোডে' আচরণ করে যেখানে Support SQLite এবং SQLite Driver API উভয়ই প্রত্যাশিতভাবে কাজ করে। এটি ক্রমবর্ধমান স্থানান্তর সক্ষম করে যাতে আপনাকে আপনার সমস্ত সমর্থন SQLite ব্যবহারগুলিকে একক পরিবর্তনে SQLite ড্রাইভারে রূপান্তর করতে হবে না।

নিম্নলিখিত উদাহরণগুলি সাপোর্ট SQLite এবং তাদের SQLite ড্রাইভারের প্রতিরূপের সাধারণ ব্যবহার:

SQLite সমর্থন করুন (থেকে)

কোনো ফলাফল ছাড়াই একটি অনুসন্ধান চালান

val database: SupportSQLiteDatabase = ...
database.execSQL("ALTER TABLE ...")

ফলাফল সহ একটি ক্যোয়ারী চালান কিন্তু কোন আর্গুমেন্ট নেই

val database: SupportSQLiteDatabase = ...
database.query("SELECT * FROM Pet").use { cursor ->
  while (cusor.moveToNext()) {
    // read columns
    cursor.getInt(0)
    cursor.getString(1)
  }
}

ফলাফল এবং আর্গুমেন্ট সহ একটি ক্যোয়ারী চালান

database.query("SELECT * FROM Pet WHERE id = ?", id).use { cursor ->
  if (cursor.moveToNext()) {
    // row found, read columns
  } else {
    // row not found
  }
}

SQLite ড্রাইভার (থেকে)

কোনো ফলাফল ছাড়াই একটি অনুসন্ধান চালান

val connection: SQLiteConnection = ...
connection.execSQL("ALTER TABLE ...")

ফলাফল সহ একটি ক্যোয়ারী চালান কিন্তু কোন আর্গুমেন্ট নেই

val connection: SQLiteConnection = ...
connection.prepare("SELECT * FROM Pet").use { statement ->
  while (statement.step()) {
    // read columns
    statement.getInt(0)
    statement.getText(1)
  }
}

ফলাফল এবং আর্গুমেন্ট সহ একটি ক্যোয়ারী চালান

connection.prepare("SELECT * FROM Pet WHERE id = ?").use { statement ->
  statement.bindInt(1, id)
  if (statement.step()) {
    // row found, read columns
  } else {
    // row not found
  }
}

ডাটাবেস লেনদেন APIs সরাসরি SupportSQLiteDatabasebeginTransaction() , setTransactionSuccessful() এবং endTransaction() সহ পাওয়া যায়। এগুলি runInTransaction() ব্যবহার করে রুমের মাধ্যমেও উপলব্ধ। SQLite ড্রাইভার API-এ এই ব্যবহারগুলি স্থানান্তর করুন।

SQLite সমর্থন করুন (থেকে)

একটি লেনদেন সম্পাদন করুন ( RoomDatabase ব্যবহার করে)

val database: RoomDatabase = ...
database.runInTransaction {
  // perform database operations in transaction
}

একটি লেনদেন সম্পাদন করুন ( SupportSQLiteDatabase ব্যবহার করে)

val database: SupportSQLiteDatabase = ...
database.beginTransaction()
try {
  // perform database operations in transaction
  database.setTransactionSuccessful()
} finally {
  database.endTransaction()
}

SQLite ড্রাইভার (থেকে)

একটি লেনদেন সম্পাদন করুন ( RoomDatabase ব্যবহার করে)

val database: RoomDatabase = ...
database.useWriterConnection { transactor ->
  transactor.immediateTransaction {
    // perform database operations in transaction
  }
}

একটি লেনদেন সম্পাদন করুন ( SQLiteConnection ব্যবহার করে)

val connection: SQLiteConnection = ...
connection.execSQL("BEGIN IMMEDIATE TRANSACTION")
try {
  // perform database operations in transaction
  connection.execSQL("END TRANSACTION")
} catch(t: Throwable) {
  connection.execSQL("ROLLBACK TRANSACTION")
}

বিভিন্ন কলব্যাক ওভাররাইডকে তাদের ড্রাইভার কাউন্টারপার্টে স্থানান্তরিত করতে হবে:

SQLite সমর্থন করুন (থেকে)

মাইগ্রেশন সাবক্লাস

object Migration_1_2 : Migration(1, 2) {
  override fun migrate(db: SupportSQLiteDatabase) {
    // ...
  }
}

অটো মাইগ্রেশন স্পেসিফিকেশন সাবক্লাস

class AutoMigrationSpec_1_2 : AutoMigrationSpec {
  override fun onPostMigrate(db: SupportSQLiteDatabase) {
    // ...
  }
}

ডাটাবেস কলব্যাক সাবক্লাস

object MyRoomCallback : RoomDatabase.Callback {
  override fun onCreate(db: SupportSQLiteDatabase) {
    // ...
  }

  override fun onDestructiveMigration(db: SupportSQLiteDatabase) {
    // ...
  }

  override fun onOpen(db: SupportSQLiteDatabase) {
    // ...
  }
}

SQLite ড্রাইভার (থেকে)

মাইগ্রেশন সাবক্লাস

object Migration_1_2 : Migration(1, 2) {
  override fun migrate(connection: SQLiteConnection) {
    // ...
  }
}

অটো মাইগ্রেশন স্পেসিফিকেশন সাবক্লাস

class AutoMigrationSpec_1_2 : AutoMigrationSpec {
  override fun onPostMigrate(connection: SQLiteConnection) {
    // ...
  }
}

ডাটাবেস কলব্যাক সাবক্লাস

object MyRoomCallback : RoomDatabase.Callback {
  override fun onCreate(connection: SQLiteConnection) {
    // ...
  }

  override fun onDestructiveMigration(connection: SQLiteConnection) {
    // ...
  }

  override fun onOpen(connection: SQLiteConnection) {
    // ...
  }
}

সংক্ষিপ্ত করার জন্য, SQLiteDatabase এর ব্যবহার প্রতিস্থাপন করুন, SQLiteConnection দিয়ে যখন একটি RoomDatabase উপলব্ধ না থাকে, যেমন কলব্যাক ওভাররাইডে ( onMigrate , onCreate , ইত্যাদি)। যদি একটি RoomDatabase উপলব্ধ থাকে, তাহলে RoomDatabase.openHelper.writtableDatabase এর পরিবর্তে RoomDatabase.useReaderConnection এবং RoomDatabase.useWriterConnection ব্যবহার করে অন্তর্নিহিত ডাটাবেস সংযোগ অ্যাক্সেস করুন।

ব্লকিং DAO ফাংশনগুলিকে ফাংশন স্থগিত করতে রূপান্তর করুন

রুম-এর KMP সংস্করণ কনফিগার করা CoroutineContext এ I/O ক্রিয়াকলাপ সম্পাদন করতে coroutine-এর উপর নির্ভর করে। এর মানে হল যে ফাংশন স্থগিত করার জন্য আপনাকে যেকোনো ব্লকিং DAO ফাংশন স্থানান্তর করতে হবে।

DAO ফাংশন ব্লক করা (থেকে)

@Query("SELECT * FROM Todo")
fun getAllTodos(): List<Todo>

DAO ফাংশন স্থগিত করা (থেকে)

@Query("SELECT * FROM Todo")
suspend fun getAllTodos(): List<Todo>

বিদ্যমান DAO ব্লকিং ফাংশনগুলিকে স্থগিত করার জন্য স্থানান্তর করা জটিল হতে পারে যদি বিদ্যমান কোডবেস ইতিমধ্যেই কোরোটিনগুলিকে অন্তর্ভুক্ত না করে। আপনার কোডবেসে coroutines ব্যবহার শুরু করতে Android-এ Coroutines পড়ুন।

প্রতিক্রিয়াশীল রিটার্ন প্রকারগুলিকে ফ্লোতে রূপান্তর করুন

সমস্ত DAO ফাংশন সাসপেন্ড ফাংশন হতে হবে না। DAO ফাংশনগুলি যেগুলি প্রতিক্রিয়াশীল প্রকারগুলি প্রদান করে যেমন LiveData বা RxJava's Flowable সাসপেন্ড ফাংশনে রূপান্তরিত করা উচিত নয়৷ কিছু প্রকার, যেমন LiveData KMP সামঞ্জস্যপূর্ণ নয়। প্রতিক্রিয়াশীল রিটার্ন প্রকারের সাথে DAO ফাংশনগুলিকে অবশ্যই কোরোটিন প্রবাহে স্থানান্তরিত করতে হবে।

বেমানান KMP প্রকার (থেকে)

@Query("SELECT * FROM Todo")
fun getTodosLiveData(): LiveData<List<Todo>>

সামঞ্জস্যপূর্ণ KMP প্রকার (থেকে)

@Query("SELECT * FROM Todo")
fun getTodosFlow(): Flow<List<Todo>>

আপনার কোডবেসে ফ্লো ব্যবহার শুরু করতে Android-এ Flows পড়ুন।

একটি করোটিন প্রসঙ্গ সেট করুন (ঐচ্ছিক)

একটি RoomDatabase ঐচ্ছিকভাবে ডাটাবেস ক্রিয়াকলাপ সম্পাদন করতে RoomDatabase.Builder.setQueryExecutor() ব্যবহার করে ভাগ করা অ্যাপ্লিকেশন নির্বাহকদের সাথে কনফিগার করা যেতে পারে। যেহেতু নির্বাহক KMP সামঞ্জস্যপূর্ণ নয়, তাই রুমের setQueryExecutor() API সাধারণ উত্সগুলির জন্য উপলব্ধ নয়৷ পরিবর্তে RoomDatabase একটি CoroutineContext দিয়ে কনফিগার করা আবশ্যক। RoomDatabase.Builder.setCoroutineContext() ব্যবহার করে একটি প্রসঙ্গ সেট করা যেতে পারে, যদি কোনোটি সেট না করা হয় তাহলে RoomDatabase ডিফল্ট হবে Dispatchers.IO ব্যবহার করে।

একটি SQLite ড্রাইভার সেট করুন

একবার Support SQLite ব্যবহার SQLite Driver API-এ স্থানান্তরিত হয়ে গেলে, RoomDatabase.Builder.setDriver ব্যবহার করে ড্রাইভারকে কনফিগার করতে হবে। প্রস্তাবিত ড্রাইভার হল BundledSQLiteDriver । উপলব্ধ ড্রাইভার বাস্তবায়নের বর্ণনার জন্য ড্রাইভার বাস্তবায়ন দেখুন।

কাস্টম SupportSQLiteOpenHelper.Factory RoomDatabase.Builder.openHelperFactory() ব্যবহার করে কনফিগার করা ফ্যাক্টরি KMP-তে সমর্থন করে না, কাস্টম ওপেন হেল্পার দ্বারা প্রদত্ত বৈশিষ্ট্যগুলি SQLite ড্রাইভার ইন্টারফেসের সাথে পুনরায় প্রয়োগ করতে হবে৷

রুম ঘোষণা সরান

মাইগ্রেশনের বেশিরভাগ ধাপ শেষ হয়ে গেলে, কেউ রুমের সংজ্ঞাগুলিকে একটি সাধারণ উৎস সেটে নিয়ে যেতে পারে। মনে রাখবেন যে expect / actual কৌশলগুলি ক্রমবর্ধমানভাবে রুম সম্পর্কিত সংজ্ঞাগুলি সরাতে ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, যদি সমস্ত ব্লকিং DAO ফাংশনগুলিকে ফাংশন স্থগিত করতে স্থানান্তরিত করা না যায়, তাহলে একটি expect @Dao টীকাযুক্ত ইন্টারফেস ঘোষণা করা সম্ভব যা সাধারণ কোডে খালি, কিন্তু Android এ ব্লকিং ফাংশন রয়েছে।

// shared/src/commonMain/kotlin/Database.kt

@Database(entities = [TodoEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
  abstract fun getDao(): TodoDao
  abstract fun getBlockingDao(): BlockingTodoDao
}

@Dao
interface TodoDao {
    @Query("SELECT count(*) FROM TodoEntity")
    suspend fun count(): Int
}

@Dao
expect interface BlockingTodoDao
// shared/src/androidMain/kotlin/BlockingTodoDao.kt

@Dao
actual interface BlockingTodoDao {
    @Query("SELECT count(*) FROM TodoEntity")
    fun count(): Int
}