שמירת נתונים במסד נתונים מקומי באמצעות Room חלק מ-Android Jetpack.

אפליקציות שמטפלות בכמויות גדולות של נתונים מובְנים יכולות להפיק תועלת רבה לשמירת הנתונים באופן מקומי. התרחיש לדוגמה הנפוץ ביותר לשימוש בחלופות הוא שמירה במטמון קטעי נתונים, כדי שכאשר המכשיר לא יוכל לגשת לרשת, המשתמש יוכל עדיין לעיין בתוכן הזה כשהם במצב אופליין.

ספריית מתמידים של חדר מספקת שכבת הפשטה מעל SQLite שמאפשרת גישה שוטפת למסדי נתונים תוך ניצול כל העוצמה של SQLite. באופן ספציפי, אלה היתרונות של החדר:

  • אימות-זמן של שאילתות SQL.
  • הערות נוחות שממזערות בקשות סטנדרטיות שחוזרות על עצמן או שעלולות לגרום לשגיאות.
  • נתיבי העברה יעילים יותר של מסדי נתונים.

בגלל השיקולים האלה, מומלץ מאוד להשתמש במקום זאת ב'חדר' של שימוש ישיר בממשקי ה-API של SQLite.

הגדרה

כדי להשתמש בחדר, צריך להוסיף את יחסי התלות הבאים לאפליקציה קובץ build.gradle:

מגניב

dependencies {
    def room_version = "2.6.1"

    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"

    // To use Kotlin annotation processing tool (kapt)
    kapt "androidx.room:room-compiler:$room_version"
    // To use Kotlin Symbol Processing (KSP)
    ksp "androidx.room:room-compiler:$room_version"

    // optional - RxJava2 support for Room
    implementation "androidx.room:room-rxjava2:$room_version"

    // optional - RxJava3 support for Room
    implementation "androidx.room:room-rxjava3:$room_version"

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation "androidx.room:room-guava:$room_version"

    // optional - Test helpers
    testImplementation "androidx.room:room-testing:$room_version"

    // optional - Paging 3 Integration
    implementation "androidx.room:room-paging:$room_version"
}

Kotlin

dependencies {
    val room_version = "2.6.1"

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

    // To use Kotlin annotation processing tool (kapt)
    kapt("androidx.room:room-compiler:$room_version")
    // To use Kotlin Symbol Processing (KSP)
    ksp("androidx.room:room-compiler:$room_version")

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

    // optional - RxJava2 support for Room
    implementation("androidx.room:room-rxjava2:$room_version")

    // optional - RxJava3 support for Room
    implementation("androidx.room:room-rxjava3:$room_version")

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation("androidx.room:room-guava:$room_version")

    // optional - Test helpers
    testImplementation("androidx.room:room-testing:$room_version")

    // optional - Paging 3 Integration
    implementation("androidx.room:room-paging:$room_version")
}

רכיבים ראשיים

החדר כולל שלושה רכיבים עיקריים:

המחלקה של מסד הנתונים מספקת לאפליקציה מכונות של DAO שמשויכות אל מסד הנתונים הזה. האפליקציה יכולה גם להשתמש ב-DAO כדי לאחזר נתונים מסד נתונים כמכונות של האובייקטים של ישות הנתונים המשויכת. האפליקציה יכולה גם להשתמש בישויות הנתונים המוגדרות כדי לעדכן שורות מהטבלאות המתאימות, או כדי ליצור שורות חדשות להזנה. איור 1 ממחיש את הקשר בין מהרכיבים השונים של החדר.

איור 1. תרשים הארכיטקטורה של ספריית החדרים.

הטמעה לדוגמה

בקטע הזה מוצגת דוגמה להטמעה של מסד נתונים מסוג Room עם וישות נתונים אחת ו-DAO אחד.

ישות נתונים

הקוד הבא מגדיר ישות נתונים מסוג User. כל מופע של User מייצג שורה בטבלה user במסד הנתונים של האפליקציה.

Kotlin

@Entity
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

Java

@Entity
public class User {
    @PrimaryKey
    public int uid;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;
}

למידע נוסף על ישויות נתונים ב'חדר', אפשר לעיין במאמר בנושא הגדרת נתונים באמצעות 'חדר'. של ישויות.

אובייקט גישה לנתונים (DAO)

הקוד הבא מגדיר DAO בשם UserDao. UserDao מספק את שיטות שבהן שאר האפליקציה משתמשת כדי לבצע אינטראקציה עם הנתונים בטבלה user.

Kotlin

@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    fun getAll(): List<User>

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    fun loadAllByIds(userIds: IntArray): List<User>

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
           "last_name LIKE :last LIMIT 1")
    fun findByName(first: String, last: String): User

    @Insert
    fun insertAll(vararg users: User)

    @Delete
    fun delete(user: User)
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
           "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}

למידע נוסף על DAOs, ראו גישה לנתונים באמצעות 'חדר' לוחצים על DAOs.

מסד נתונים

הקוד הבא מגדיר מחלקה AppDatabase שתכיל את מסד הנתונים. AppDatabase קובע את ההגדרה של מסד הנתונים ומשמש כערך הראשי של האפליקציה נקודת הגישה לנתונים הקבועים. המחלקה של מסד הנתונים חייבת לעמוד בדרישות של את התנאים הבאים:

  • צריך להוסיף לכיתה הערות @Database כולל entities מערך שמפרט את כל ישויות הנתונים שמשויכות למסד הנתונים.
  • המחלקה חייבת להיות מחלקה מופשטת שמתרחבת RoomDatabase
  • לכל מחלקה של DAO שמשויכת למסד הנתונים, המחלקה של מסד הנתונים חייבת להגדיר שיטה מופשטת שיש בה אפס ארגומנטים ומחזירה מופע של מחלקת ה-DAO.

Kotlin

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

Java

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

הערה: אם האפליקציה פועלת בתהליך אחד, צריך לפעול לפי תבנית עיצוב סינגלטון כאשר יוצרים AppDatabase לאובייקט. כל מכונה של RoomDatabase יקרה למדי, רק לעיתים רחוקות צריכה גישה למספר מופעים בתהליך יחיד.

אם האפליקציה פועלת בכמה תהליכים, צריך לכלול enableMultiInstanceInvalidation() בכלי ליצירת מסדי נתונים הפעלה. כך, כשיש מופע של AppDatabase בכל תהליך, תוכלו לבטל את התוקף של קובץ מסד הנתונים המשותף בתהליך אחד, וביטול התוקף הזה מופץ באופן אוטומטי במקרים של AppDatabase בתהליכים אחרים.

שימוש

אחרי שהגדרתם את ישות הנתונים, את מחלקת התפעול (DAO) ואת אובייקט מסד הנתונים, יכול להשתמש בקוד הבא כדי ליצור מכונה של מסד הנתונים:

Kotlin

val db = Room.databaseBuilder(
            applicationContext,
            AppDatabase::class.java, "database-name"
        ).build()

Java

AppDatabase db = Room.databaseBuilder(getApplicationContext(),
        AppDatabase.class, "database-name").build();

לאחר מכן אפשר להשתמש בשיטות מופשטות מה-AppDatabase כדי לקבל מופע של DAO. לאחר מכן, אפשר להשתמש ב-methods ממכונת ה-DAO כדי ליצור אינטראקציה במסד הנתונים:

Kotlin

val userDao = db.userDao()
val users: List<User> = userDao.getAll()

Java

UserDao userDao = db.userDao();
List<User> users = userDao.getAll();

מקורות מידע נוספים

למידע נוסף על Room, אפשר לעיין במקורות המידע הנוספים הבאים:

דוגמיות

שיעורי Lab

בלוגים