,

Room, اتصال به دیتابیس در اندروید

Room, اتصال به دیتابیس در اندروید

سلام دوستان عزیز! امروز می‌خوایم با هم یکی از قدرتمندترین ترکیب‌ها در دنیای اندروید رو بررسی کنیم: Room + KSP + Jetpack Compose. این سه تکنولوژی با هم ترکیب می‌شن تا توسعه اپلیکیشن‌های اندرویدی رو خیلی راحت‌تر و سریع‌تر کنن.

توی این مقاله، قصد دارم نحوه پیاده‌سازی این ترکیب رو با مثالهای کاربردی بهتون آموزش بدم. اما قبلش اگه با دیتابیسهای SQL آشناییت ندارید حتما یک آموزش کوتاه از دیتابیس SQLite ببینید و همچنین اگه هنوز با ViewModel در JetPack Compose آشنا نیستید، حتما این آموزش رو نگاه کنید.

Room + Jetpack Compose

آشنایی با Room

Room یک کتابخانه از خانواده Jetpack اندرویده که به عنوان یک لایه انتزاعی (ORM) روی SQLite عمل می‌کنه. این کتابخانه به ما اجازه می‌ده تا به راحتی با دیتابیس کار کنیم و از مزایای زیر بهره‌مند بشیم:

بررسی کوئری‌ها در زمان کامپایل

کوئری‌های SQL شما در زمان کامپایل بررسی می‌شن و خطاها زودتر شناسایی می‌شن.

کاهش کدهای تکراری

با استفاده از annotation، کدهای تکراری کاهش پیدا می‌کنن و توسعه سریع‌تر می‌شه.

مسیرهای ساده‌شده برای مهاجرت

فرآیند migration دیتابیس با Room بسیار ساده‌تر و قابل مدیریت‌تره.

یکپارچه‌سازی با Jetpack

Room به خوبی با سایر اجزای Jetpack مانند LiveData و Flow یکپارچه می‌شه.

اجزای اصلی Room

Room از سه جزء اصلی تشکیل شده:

1. Entity (موجودیت)

Entity نماینده یک جدول در دیتابیس هست. هر Entity با @Entity مشخص می‌شه و شامل فیلدهایی هست که ستون‌های جدول رو تشکیل می‌دن.

@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    @ColumnInfo(name = "name")
    val name: String,
    @ColumnInfo(name = "email")
    val email: String
)

2. DAO (Data Access Object)

DAO شامل متدهایی برای دسترسی به دیتابیس هست. این متدها با انوتیشن‌هایی مثل @Query، @Insert، @Update و @Delete مشخص می‌شن.

@Dao
interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: User)
    
    @Query("SELECT * FROM users")
    suspend fun getAllUsers(): List<User>
    
    @Query("SELECT * FROM users WHERE id = :id")
    suspend fun getUserById(id: Int): User?
}

3. Database

Database کلاسی هست که به عنوان نقطه دسترسی اصلی به دیتابیس عمل می‌کنه. این کلاس باید از RoomDatabase ارث‌بری کنه و با انوتیشن @Database مشخص بشه.

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}
Room Database Architecture
دیتابیس روم در اندروید

KSP چیست؟

KSP یا Kotlin Symbol Processing یک ابزار پردازش انوتیشن برای کد Kotlin هست. KSP سریع‌تر و کارآمدتر ازKAPT (که قبلا استفاده می شد) عمل می‌کنه.

ویژگیKSPKAPT
سرعتتا ۲ برابر سریع‌ترکندتر
یکپارچه‌سازیمستقیم با کامپایلر Kotlinنیاز به تولید Java stubs
درک کددرک بهتر از ساختارهای Kotlinمحدودیت در درک کد Kotlin
وابستگی به JVMوابستگی کمتروابستگی بیشتر

نکته: گوگل به طور رسمی KSP را به عنوان جایگزین KAPT معرفی کرده و توصیه می‌کنه که در پروژه‌های جدید از KSP استفاده بشه.

KSP vs KAPT

قبل از اینکه بخوایم دیتابیس Room رو اضافه کنیم، لازم هست تا KSP رو به پروژه اضافه کرده باشیم.

نحوه استفاده از KSP :

برای استفاده از KSP ، باید مراحل زیر رو طی کنید:

1_ افزودن پلاگین KSP (مشاهده آخرین نسخه و تغییرات)

// در فایل build.gradle.kts سطح پروژه
plugins {
    id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
}

2_ اعمال پلاگین در module-level :

// در فایل build.gradle.kts ماژول
plugins {
    id("com.google.devtools.ksp")
}

پیاده‌سازی Room:

حالا نوبت به Room می رسه:

1- افزودن پلاگین روم:

plugins {
    id("androidx.room") version "$room_version" apply false
}

2- اعمال پلاگین در module-level :

plugins {
...
    id("androidx.room")
}
dependencies {
    val room_version = "2.7.2"

    implementation("androidx.room:room-runtime:$room_version")
    ksp("androidx.room:room-compiler:$room_version")

    // If this project only uses Java source, use the Java annotationProcessor
    // No additional plugins are necessary
    annotationProcessor("androidx.room:room-compiler:$room_version")

    // optional - Kotlin Extensions and Coroutines support for Room
    implementation("androidx.room:room-ktx:$room_version")
}

android {
    ...
    room {
        schemaDirectory("$projectDir/schemas")
    }
}

تنظیم schemaDirectory هنگام استفاده از افزونه Room Gradle الزامی است. این کار کامپایلر Room و وظایف مختلف کامپایل و backend های آن (javac، KAPT، KSP) را طوری پیکربندی می‌کند که فایل‌های schema را در پوشه‌های flavored، به عنوان مثال schemas/flavorOneDebug/com.package.MyDatabase/1.json، خروجی دهد. این فایل‌ها باید در مخزن بررسی شوند تا برای اعتبارسنجی و مهاجرت خودکار استفاده شوند.

۳- تعریف Entity :

ما قصد داریم تا یک سیستم ورود آفلاین کاربر بسازیم که ایمیل و کلمه عبورش رو در دیتابیس بررسی کنیم اگر وجود داره، وارد حساب کاربریش بشه، برای اینکار لازم داریم تا یه جدول از کاربرهامون در دیتابیسمون داشته باشیم:

@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true) val id: Int,
val name: String,
val password: String,
val mail: String,
val phone: String,
)

۴ـ تعریف DAO

@Dao
interface UserDAO {
@Insert
suspend fun insert(user: User)

@Query("SELECT * FROM users WHERE mail = :mail AND password = :password")
suspend fun getUser(mail: String, password: String): User?

@Query("SELECT * FROM users ")
suspend fun getAllUsers(): List<User>
}

۵- تعریف Database

@Database(entities = [User::class], version = 1, exportSchema = true)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDAO(): UserDAO
}
  1. abstract class AppDatabase : RoomDatabase():
    • abstract class AppDatabase: این کلاس رو abstract تعریف کردن چون قراره خودش مستقیم ساخته نشه. روم خودش یه نسخه‌ی پیاده‌سازی شده از این کلاس رو پشت صحنه می‌سازه.
    • : RoomDatabase(): این کلاس از RoomDatabase ارث‌بری می‌کنه. RoomDatabase کلاس پایه‌ی روم برای مدیریت دیتابیسه
  2. @Database(entities = [User::class], version = 1):
    • @Database: این یه انوتیشن (Annotation) مخصوص رومه. به Room میگه: “ببین این کلاس، کلاس اصلی دیتابیس ماست!”
    • entities = [User::class]: اینجا مشخص می‌کنه که دیتابیس ما قراره چند تا جدول (Entity) داشته باشه. اینجا فقط یه جدول به اسم User داریم.
    • version = 1: اینم شماره نسخه‌ی دیتابیس. هر وقت بخوای ساختار جدول‌ها رو عوض کنی (مثلاً یه ستون جدید اضافه کنی یا یه جدول جدید بسازی)، باید این شماره رو افزایش بدی (مثلاً بکنی 2) تا روم متوجه تغییرات بشه.

استفاده در ViewModel

خب حالا که دیتابیسمون رو تعریف کردیم باید در ویومدلمون ازش استفاده کنیم که نیاز به Hilt برای تزریق وابستگی ها به ویو مدل داریم. از اونجا که این مطلبمون خیلی طولانی شده، این موضوع رو در یک پست جداگونه ادامه می دم.

Comments

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *