Room হল Android-এ SQLite-এর সাথে কাজ করার জন্য একটি লাইব্রেরি, যা Jetpack-এর অংশ। এটি কাঁচা SQLite-এর উপর একটি অ্যাবস্ট্রাকশন লেয়ার প্রদান করে, টেবিল তৈরি, কোয়েরি নির্বাহ এবং Kotlin ও Java অবজেক্টে ডেটা রূপান্তর স্বয়ংক্রিয় করে। Android Developers অনুসারে, Room বিল্ড টাইমে SQL কোয়েরি কম্পাইল করে, সিনট্যাক্স সঠিকতা এবং Entity ও টেবিলের মধ্যে সম্পর্ক যাচাই করে।
মূল পয়েন্ট
Room হল Android Jetpack-এর একটি পার্সিস্টেন্স লাইব্রেরি যা SQLite-এর জন্য অবজেক্ট-রিলেশনাল ম্যাপিং প্রদান করে। Room কাঁচা SQLite-এর তিনটি প্রধান সমস্যা সমাধান করে: টেবিল তৈরির জন্য প্রচুর boilerplate কোড লেখা, কম্পাইল টাইমে SQL কোয়েরি যাচাইয়ের অভাব, এবং Cursor-কে ম্যানুয়ালি অবজেক্টে রূপান্তর করা।
লাইব্রেরিটি একটি অ্যানোটেশন প্রসেসর (kapt বা KSP) ব্যবহার করে যা বিল্ড টাইমে অ্যাবস্ট্র্যাক্ট RoomDatabase এবং DAO ক্লাসের ইমপ্লিমেন্টেশন জেনারেট করে। এটি নিশ্চিত করে যে SQL-এ সিনট্যাক্স ত্রুটি এবং টাইপ অমিল অ্যাপ্লিকেশন চালানোর আগেই শনাক্ত হয়, Google Play-তে প্রকাশের পরে রানটাইমে নয়।
Google I/O 2023 অনুসারে, Room ব্যবহার করা হয় 68% Android অ্যাপ্লিকেশনে যা লোকাল ডেটা নিয়ে কাজ করে। এটি ডিভাইসে ডেটা স্টোরেজের মান, যা Google দ্বারা সমস্ত নতুন প্রজেক্টের জন্য সুপারিশ করা হয় — পুরনো SQLiteOpenHelper এবং ContentProvider-এর পরিবর্তে।
Room-কে সেই প্রজেক্টে অন্তর্ভুক্ত করুন যেখানে সার্ভার থেকে লোকাল ডেটা ক্যাশিং, অফলাইন মোড, বা জটিল SQL কোয়েরি চালানোর ক্ষমতা সহ কাঠামোবদ্ধ ব্যবহারকারী ডেটা সংরক্ষণের প্রয়োজন রয়েছে।
Room Android Jetpack-এর অংশ এবং Google-এর দ্বারা লোকাল ডেটা নিয়ে কাজ করা সমস্ত নতুন প্রজেক্টের জন্য অফিসিয়ালি সুপারিশ করা হয়। Realm বা ObjectBox-এর বিপরীতে, Room নেটিভ SQLite ব্যবহার করে, যা DB Browser থেকে DataGrip পর্যন্ত যেকোনো তৃতীয়-পক্ষের ডাটাবেস টুলের সাথে সামঞ্জস্য নিশ্চিত করে। ডেভেলপাররা অ্যাপ্লিকেশনের .db ফাইল খুলতে পারেন এবং সরাসরি SQL কোয়েরি চালাতে পারেন, যা ডেভেলপমেন্টের সময় ডিবাগিং এবং ডেটা বিশ্লেষণ সহজ করে।
Entity হল @Entity দ্বারা অ্যানোটেটেড একটি ডেটা ক্লাস যা Room ডাটাবেস টেবিলে রূপান্তরিত করে। ক্লাসের প্রতিটি ফিল্ড টেবিলের একটি কলাম হয়ে যায়, এবং প্রতিটি ইনস্ট্যান্স একটি সারি হয়ে যায়। Room ফিল্ড অ্যাক্সেস করতে রিফ্লেকশন ব্যবহার করে, তাই বাধ্যতামূলক আইডেন্টিফায়ারের জন্য @PrimaryKey অ্যানোটেশন প্রয়োজন।
@Entity অ্যানোটেশন Room-কে জানায় যে ক্লাসটি একটি টেবিল। tableName প্যারামিটারটি টেবিলের নাম সেট করে যদি এটি ক্লাসের নাম থেকে আলাদা হয়। @PrimaryKey autoGenerate = true-এর মাধ্যমে অটো-জেনারেশন সমর্থন সহ প্রাইমারি কী নির্ধারণ করে।
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
@ColumnInfo(name = "full_name")
val name: String,
@Ignore
val tempData: String?
)
@ColumnInfo টেবিলে কলামের নাম নির্দিষ্ট করে যদি এটি Kotlin ফিল্ডের নাম থেকে আলাদা হয়। @Ignore একটি ফিল্ডকে টেবিল থেকে বাদ দেয় — এটি ডাটাবেসে সংরক্ষিত হবে না। @ForeignKey ডিলিট বা আপডেটে ক্যাসকেড অপারেশন সহ টেবিলের মধ্যে সম্পর্কের জন্য ফরেন কী বর্ণনা করে।
Room @Embedded অ্যানোটেশনের মাধ্যমে নেস্টেড অবজেক্ট সমর্থন করে। নেস্টেড ক্লাসের ফিল্ডগুলি নাম দ্বন্দ্ব এড়াতে প্রিফিক্স সহ প্যারেন্ট টেবিলের কলামে প্রসারিত হয়। উদাহরণস্বরূপ, User-এ এম্বেড করা city এবং street ফিল্ড সহ Address ক্লাস users টেবিলে address_city এবং address_street কলাম তৈরি করবে, সরল ভ্যালু অবজেক্টের জন্য আলাদা টেবিলের প্রয়োজনীয়তা দূর করে।
Room শুধুমাত্র প্রিমিটিভ টাইপ এবং তাদের র্যাপার সমর্থন করে। লিস্ট, Date বা কাস্টম টাইপ সংরক্ষণ করতে, @TypeConverter ব্যবহার করুন — কাস্টম টাইপ এবং SQLite প্রিমিটিভের মধ্যে রূপান্তরের জন্য স্ট্যাটিক মেথড, উদাহরণস্বরূপ, List এবং JSON স্ট্রিংয়ের মধ্যে।
DAO (ডেটা অ্যাক্সেস অবজেক্ট) হল @Dao দ্বারা অ্যানোটেটেড একটি ইন্টারফেস বা অ্যাবস্ট্র্যাক্ট ক্লাস যা ডেটা অ্যাক্সেসের জন্য মেথড ধারণ করে। প্রতিটি মেথড একটি SQL অপারেশন দিয়ে অ্যানোটেটেড: @Insert, @Update, @Delete বা স্পষ্ট SQL কোয়েরি সহ @Query।
@Query অ্যানোটেশন একটি SQL স্ট্রিং নেয় যা Room কম্পাইল টাইমে সিনট্যাক্স সঠিকতা এবং Entity ফিল্ডের সাথে কলামের নাম মিলানোর জন্য যাচাই করে। Room :paramName সিনট্যাক্সের মাধ্যমে প্যারামিটারাইজড কোয়েরি সমর্থন করে।
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: Int): User?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("SELECT * FROM users ORDER BY name ASC")
fun getAllUsers(): Flow<List<User>>
}
@Insert ডুপ্লিকেট রেকর্ড সন্নিবেশ করার সময় দ্বন্দ্ব সামাল দেওয়ার জন্য OnConflictStrategy বিকল্পগুলি সমর্থন করে। Flow রিটার্ন টাইপ হিসাবে টেবিলে প্রতিটি ডেটা পরিবর্তনে রিঅ্যাকটিভ UI আপডেট প্রদান করে — সাবস্ক্রিপশন যেকোনো INSERT, UPDATE বা DELETE-এ স্বয়ংক্রিয়ভাবে পুনরায় শুরু হয়।
@Transaction অ্যানোটেশন একটি একক ট্রানজেকশনাল ব্লকের মধ্যে একাধিক অপারেশনের পারমাণবিক নির্বাহ নিশ্চিত করে। Room নির্বাহের সময় ডাটাবেস লক করে, একাধিক থ্রেড থেকে সমবর্তী অ্যাক্সেসের সময় রেস কন্ডিশন প্রতিরোধ করে।
RoomDatabase হল একটি অ্যাবস্ট্র্যাক্ট ক্লাস যা Entity এবং DAO-কে একটি একক ডাটাবেস অ্যাক্সেস পয়েন্টে একত্রিত করে। এটি স্কিমা সংস্করণ এবং Entity ক্লাসের তালিকা সহ Room.databaseBuilder-এর মাধ্যমে তৈরি করা হয়। একাধিক সংযোগ এড়াতে ডাটাবেস ইনস্ট্যান্সটি lazy ডেলিগেটের মাধ্যমে সিঙ্গেলটন হিসাবে তৈরি করা উচিত।
Room-এ মাইগ্রেশন হল একটি Migration ক্লাস যা পুরনো স্কিমা সংস্করণ থেকে নতুনতে রূপান্তরের জন্য SQL স্ক্রিপ্ট বর্ণনা করে। যদি স্কিমা পরিবর্তনের সময় মাইগ্রেশন প্রদান করা না হয়, Room IllegalStateException নিক্ষেপ করে। এটি অ্যাপ্লিকেশন আপডেট করার সময় আকস্মিক ব্যবহারকারী ডেটা ক্ষতি থেকে রক্ষা করে।
val migration_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0")
}
}
val db = Room.databaseBuilder(
getApplication(),
AppDatabase::class.java,
"app_database"
).addMigrations(migration_1_2)
.build()
ডেভেলপমেন্টের জন্য, আপনি fallbackToDestructiveMigration ব্যবহার করতে পারেন, যা সংস্করণ অমিলে পুরনো ডাটাবেস মুছে ফেলে এবং নতুন তৈরি করে। এই মোডটি শুধুমাত্র ডিবাগিংয়ের জন্য — প্রোডাকশন রিলিজে সঠিক মাইগ্রেশন অন্তর্ভুক্ত করা আবশ্যক।
ডাটাবেস পরীক্ষার জন্য, Room একটি বিশেষ ক্লাস Room.inMemoryTestBuilder প্রদান করে যা ডিস্কে সংরক্ষণ না করে মেমরিতে ডাটাবেস তৈরি করে। প্রতিটি পরীক্ষা শেষ হওয়ার পরে, ডাটাবেস স্বয়ংক্রিয়ভাবে ধ্বংস হয়ে যায়, যা পরীক্ষার দৃশ্যের সম্পূর্ণ বিচ্ছিন্নতা নিশ্চিত করে। android-arch-core-testিং লাইব্রেরির সাথে একত্রে, ডেভেলপাররা ম্যানুয়ালি স্টেট পরিষ্কার না করেই ডাটাবেস লাইফসাইকেল পরিচালনা করতে এবং মাইগ্রেশন সঠিকতা যাচাই করতে পারেন।
Room-এর কর্মক্ষমতা সরাসরি কোয়েরি গঠন এবং ইনডেক্সের উপর নির্ভর করে। ধীর কোয়েরি বিশ্লেষণের জন্য, Room enableQueryCallback ফ্ল্যাগ প্রদান করে, যা নির্বাহের সময় সহ সমস্ত SQL কোয়েরি লগ করে। ডেভেলপাররা এই লগ ব্যবহার করে 100 মিলিসেকেন্ডের বেশি সময় নেওয়া কোয়েরি খুঁজে পেতে এবং @Entity-তে @Index অ্যানোটেশনের মাধ্যমে কম্পোজিট ইনডেক্স যোগ করে বা @Relation ব্যবহার করে সাবকোয়েরি সরাসরি JOIN অপারেশনে পুনরায় লিখে সেগুলি অপ্টিমাইজ করতে পারেন।
Room SQLCipher-এর মাধ্যমে ডাটাবেস এনক্রিপশনও সমর্থন করে। net.zetetic:android-database-sqlcipher লাইব্রেরি যোগ করা এবং স্ট্যান্ডার্ডের পরিবর্তে SupportFactory ব্যবহার DAO কোয়েরি বা Entity গঠন পরিবর্তন না করেই ডিস্কের সমস্ত ডেটার স্বচ্ছ এনক্রিপশন প্রদান করে। এটি ব্যবহারকারীদের ব্যক্তিগত ডেটা হ্যান্ডল করা অ্যাপ্লিকেশনের জন্য প্রয়োজনীয় এবং GDPR এবং ব্যক্তিগত ডেটা সুরক্ষার উপর রাশিয়ান ফেডারেল আইন 152-FZ মেনে চলে। এনক্রিপশন পাসওয়ার্ড রুটেড ডিভাইসে টুলিংয়ের মাধ্যমে নিষ্কাশন থেকে রক্ষা করতে Android Keystore-এ সংরক্ষণ করা যেতে পারে।
Room সংস্করণ 2.1 থেকে Kotlin Coroutines-কে নেটিভলি সমর্থন করে। DAO মেথডগুলি suspend ফাংশন হতে পারে যা মূল থ্রেড ব্লক না করে ব্যাকগ্রাউন্ড থ্রেডে কোয়েরি নির্বাহ করে। Room স্বয়ংক্রিয়ভাবে ডিসপ্যাচার পরিচালনা করে, পড়া এবং লেখার কোয়েরির জন্য Dispatchers.IO ব্যবহার করে।
রিঅ্যাকটিভ কোয়েরির জন্য, Room একটি Flow রিটার্ন করে — একটি কোল্ড ডেটা স্ট্রিম যা প্রভাবিত টেবিলের প্রতিটি পরিবর্তনে একটি নতুন মান নির্গত করে। ViewModel stateIn বা collect-এর মাধ্যমে Flow-এ সাবস্ক্রাইব করে, অ্যাডাপ্টারকে ম্যানুয়ালি জানানো ছাড়াই স্বয়ংক্রিয় UI আপডেট প্রদান করে।
Room একটি বিশেষ PagingSource ইমপ্লিমেন্টেশনের মাধ্যমে Paging 3-ও সমর্থন করে যা SQLite থেকে পেজ অনুযায়ী ডেটা লোড করে। এটি হাজার হাজার রেকর্ড সহ বড় তালিকার জন্য কার্যকর: Paging 3 শুধুমাত্র স্ক্রিনে দৃশ্যমান সারি লোড করে এবং ডাটাবেস পরিবর্তনে স্বয়ংক্রিয়ভাবে সেগুলি আপডেট করে।
সংবাদ ফিড, অপারেশন লগ বা অফলাইন অ্যাক্সেস এবং অসীম স্ক্রোলিং সহ পণ্য তালিকা প্রদর্শনের জন্য Room-এর সাথে Paging 3 ব্যবহার করুন।
সচরাচর জিজ্ঞাসিত প্রশ্ন
Room টেবিল তৈরি, Cursor-থেকে-অবজেক্ট রূপান্তর এবং কম্পাইল টাইমে SQL যাচাই স্বয়ংক্রিয় করে। SQLiteOpenHelper-এ ম্যানুয়ালি স্কিমা লিখতে হয়, Cursor হ্যান্ডল করতে হয় এবং অ্যাপ্লিকেশন চালানোর আগে কোয়েরি যাচাই থাকে না, যা ত্রুটির ঝুঁকি বাড়ায়।
হ্যাঁ, Entity পরিবর্তন করার সময় (ফিল্ড যোগ/মুছে ফেলা, টাইপ পরিবর্তন), মাইগ্রেশন প্রয়োজন। এটি ছাড়া, Room স্টার্টআপে IllegalStateException নিক্ষেপ করে। ডেভেলপমেন্টের জন্য, আপনি fallbackToDestructiveMigration সক্ষম করতে পারেন, কিন্তু প্রোডাকশন রিলিজে সঠিক মাইগ্রেশন স্ক্রিপ্ট প্রয়োজন।
Room ক্যাসকেড অপারেশনের জন্য @ForeignKey এবং নেস্টেড অবজেক্টের জন্য @Relation সমর্থন করে। জটিল JOIN কোয়েরির জন্য, @Embedded এবং @Relation-এর মাধ্যমে নেস্টেড এন্টিটি সহ POJO রিটার্নকারী @Query-এর সাথে @Transaction অ্যানোটেশন ব্যবহার করুন।
হ্যাঁ, Room Java-এর সাথে সম্পূর্ণ সামঞ্জস্যপূর্ণ। suspend ফাংশনের পরিবর্তে LiveData বা RxJava Observable ব্যবহার করুন; Flow-এর পরিবর্তে LiveData ব্যবহার করুন। Java-এর সাথে Room সমস্ত একই অ্যানোটেশন সমর্থন করে, কিন্তু অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য আরও boilerplate কোড প্রয়োজন।
Room Zetetic-এর SQLCipher-এর মাধ্যমে এনক্রিপশন সমর্থন করে। Room.databaseBuilder-এর পরিবর্তে, net.zetetic:android-database-sqlcipher লাইব্রেরি থেকে SupportFactory ব্যবহার করুন, এনক্রিপশন পাসওয়ার্ড পাস করুন। ডিস্কের সমস্ত ডেটা DAO কোয়েরির জন্য স্বচ্ছভাবে এনক্রিপ্ট হবে।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন