כתיבת שאילתות DAO אסינכרוניות

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

שאילתות DAO מחולקות לשלוש קטגוריות:

  • שאילתות כתיבה חד-פעמית שמוסיפות, מעדכנות או מוחקות נתונים במסד הנתונים.
  • שאילתות קריאה חד-פעמית שקוראות נתונים מהמסד נתונים רק פעם אחת ומחזירות תוצאה עם תמונת המצב של המסד נתונים באותו זמן.
  • שאילתות Observable read שקוראות נתונים ממסד הנתונים בכל פעם ששינויים מתרחשים בטבלאות הבסיסיות של מסד הנתונים, ומפיקות ערכים חדשים כדי לשקף את השינויים האלה.

אפשרויות שפה ותבנית

Room מספק תמיכה בשילוב עם ספריות ותכונות ספציפיות לשפה. בטבלה הבאה מוצגים סוגי ההחזרים הרלוונטיים בהתאם לסוג השאילתה ולמסגרת:

סוג השאילתה תכונות השפה של Kotlin RxJava גויאבה Jetpack Lifecycle
כתיבה חד-פעמית פונקציות רפיטיביות (suspend) Single<T>, Maybe<T>, Completable ListenableFuture<T> לא רלוונטי
קריאה חד-פעמית פונקציות רפיטיביות (suspend) Single<T>, Maybe<T> ListenableFuture<T> לא רלוונטי
קריאה גלויה Flow<T> Flowable<T>, Publisher<T>, Observable<T> לא רלוונטי LiveData<T>

במדריך הזה מפורטות שלוש דרכים אפשריות להשתמש בשילובים האלה כדי להטמיע שאילתות אסינכררוניות ב-DAOs.

Kotlin עם Flow ושגרות המשך (coroutines)

ב-Kotlin יש תכונות שפה שמאפשרות לכתוב שאילתות אסינכרוניות בלי מסגרות של צד שלישי:

  • ב-Room 2.2 ואילך, אפשר להשתמש בפונקציונליות של Flow ב-Kotlin כדי לכתוב שאילתות שניתן לצפות בהן.
  • ב-Room 2.1 ואילך, אפשר להשתמש במילות המפתח suspend כדי להפוך את השאילתות של ה-DAO לאסינכרוניות באמצעות פונקציות רפיטיביות (coroutines) ב-Kotlin.

Java עם RxJava

אם באפליקציה שלכם נעשה שימוש בשפת התכנות Java, תוכלו להשתמש בסוגי החזרה מיוחדים מהמסגרת RxJava כדי לכתוב שיטות DAO אסינכרוניות. ב-Room יש תמיכה בסוגי ההחזרים הבאים של RxJava 2:

בנוסף, בגרסה 2.3 ואילך של Room יש תמיכה ב-RxJava 3.

Java עם LiveData ו-Guava

אם באפליקציה שלכם נעשה שימוש בשפת התכנות Java ואתם לא רוצים להשתמש ב-RxJava framework, תוכלו להשתמש בחלופות הבאות כדי לכתוב שאילתות אסינכרוניות:

  • אפשר להשתמש בכיתה המעטפת LiveData מ-Jetpack כדי לכתוב שאילתות ניתנות למעקב אסינכרוני.
  • אפשר להשתמש ב-wrapper‏ ListenableFuture<T> מ-Guava כדי לכתוב שאילתות אסינכררוניות חד-פעמיות.

כתיבת שאילתות חד-פעמיות אסינכרוניות

שאילתות חד-פעמיות הן פעולות במסד נתונים שפועלות רק פעם אחת ומפיקות קובץ snapshot של הנתונים בזמן הביצוע. ריכזנו כאן כמה דוגמאות לשאילתות חד-פעמיות אסינכרניות:

Kotlin

@Dao
interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUsers(vararg users: User)

    @Update
    suspend fun updateUsers(vararg users: User)

    @Delete
    suspend fun deleteUsers(vararg users: User)

    @Query("SELECT * FROM user WHERE id = :id")
    suspend fun loadUserById(id: Int): User

    @Query("SELECT * from user WHERE region IN (:regions)")
    suspend fun loadUsersByRegion(regions: List<String>): List<User>
}

Java

@Dao
public interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public Completable insertUsers(List<User> users);

    @Update
    public Completable updateUsers(List<User> users);

    @Delete
    public Completable deleteUsers(List<User> users);

    @Query("SELECT * FROM user WHERE id = :id")
    public Single<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public Single<List<User>> loadUsersByRegion(List<String> regions);
}

Java

@Dao
public interface UserDao {
    // Returns the number of users inserted.
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public ListenableFuture<Integer> insertUsers(List<User> users);

    // Returns the number of users updated.
    @Update
    public ListenableFuture<Integer> updateUsers(List<User> users);

    // Returns the number of users deleted.
    @Delete
    public ListenableFuture<Integer> deleteUsers(List<User> users);

    @Query("SELECT * FROM user WHERE id = :id")
    public ListenableFuture<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public ListenableFuture<List<User>> loadUsersByRegion(List<String> regions);
}

כתיבת שאילתות שניתן לצפות בהן

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

Kotlin

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    fun loadUserById(id: Int): Flow<User>

    @Query("SELECT * from user WHERE region IN (:regions)")
    fun loadUsersByRegion(regions: List<String>): Flow<List<User>>
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    public Flowable<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public Flowable<List<User>> loadUsersByRegion(List<String> regions);
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    public LiveData<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public LiveData<List<User>> loadUsersByRegion(List<String> regions);
}

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

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

בלוגים