התכונה 'חדר' מספקת פונקציונליות להמרה בין סוגים פרימיטיביים ומקיפים אבל היא לא מאפשרת הפניות אובייקטים בין ישויות. המסמך הזה מסבירה איך להשתמש בממירים של סוגי המשתנים ולמה Room לא תומך באובייקטים הפניות.
שימוש בממירים
לפעמים צריך שהאפליקציה שלך תאחסן סוג נתונים מותאם אישית במסד נתונים יחיד
עמודה. כדי לתמוך בסוגים מותאמים אישית, אתם צריכים לספק ממירים של סוגי המרות.
שיטות שמסבירות ל- Room איך להמיר סוגים מותאמים אישית לסוגים מוכרים
החדר יכול להימשך. אתה מזהה ממירים לפי סוג
@TypeConverter
.
נניח שצריך לשמור מופעים של Date
מסד הנתונים Room. החדר לא יודע איך לשמור Date
אובייקטים, לכן צריך
כדי להגדיר סוגי ממירים:
Kotlin
class Converters { @TypeConverter fun fromTimestamp(value: Long?): Date? { return value?.let { Date(it) } } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time?.toLong() } }
Java
public class Converters { @TypeConverter public static Date fromTimestamp(Long value) { return value == null ? null : new Date(value); } @TypeConverter public static Long dateToTimestamp(Date date) { return date == null ? null : date.getTime(); } }
בדוגמה זו מוגדרות שתי שיטות להמרת סוגים: אחת שממירה Date
לאובייקט Long
, ואובייקט שמבצע את ההמרה ההפוכה
Long
עד Date
. מכיוון שהחדר יודע איך לשמור על Long
אובייקטים, הוא יכול להשתמש
ממירים אלה כדי לשמור Date
אובייקטים.
בשלב הבא, מוסיפים את @TypeConverters
הערה לכיתה AppDatabase
כדי ש- Room ידע על הממיר
המחלקה שהגדרתם:
Kotlin
@Database(entities = [User::class], version = 1) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
Java
@Database(entities = {User.class}, version = 1) @TypeConverters({Converters.class}) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
כשמוגדרים ממירים מהסוג הזה, אפשר להשתמש בסוג המותאם אישית של ישויות ושל dAOs בדיוק כמו שמשתמשים בסוגים ראשוניים:
Kotlin
@Entity data class User(private val birthday: Date?) @Dao interface UserDao { @Query("SELECT * FROM user WHERE birthday = :targetDate") fun findUsersBornOnDate(targetDate: Date): List<User> }
Java
@Entity public class User { private Date birthday; } @Dao public interface UserDao { @Query("SELECT * FROM user WHERE birthday = :targetDate") List<User> findUsersBornOnDate(Date targetDate); }
בדוגמה הזו, חדר יכול להשתמש בממיר הסוג המוגדר בכל מקום, כי
הוספת הערות ל-AppDatabase
עם @TypeConverters
. עם זאת, אפשר גם להשתמש בסוג ההיקף
ממירים לישויות או אדמינים ספציפיים (DAOs) על ידי הוספת הערות ל@Entity
או ל@Dao
עם @TypeConverters
.
אתחול הממיר של סוג הבקרה
בדרך כלל, חדר מטפל עבורכם ביצירת ממירים של סוגים. אבל, לפעמים
לפעמים ייתכן שתצטרכו להעביר יחסי תלות נוספים לממיר סוג ההמרה
כלומר, אתם צריכים שהאפליקציה שלכם תוכל לשלוט ישירות באתחול
מסוג ממירים. במקרה כזה, כדאי להוסיף הערות למחלקה של הממיר עם
@ProvidedTypeConverter
:
Kotlin
@ProvidedTypeConverter class ExampleConverter { @TypeConverter fun StringToExample(string: String?): ExampleType? { ... } @TypeConverter fun ExampleToString(example: ExampleType?): String? { ... } }
Java
@ProvidedTypeConverter public class ExampleConverter { @TypeConverter public Example StringToExample(String string) { ... } @TypeConverter public String ExampleToString(Example example) { ... } }
לאחר מכן, בנוסף להצהרה על שיעור ההמרה של @TypeConverters
, משתמשים
ה
RoomDatabase.Builder.addTypeConverter()
כדי להעביר מופע של מחלקת הממירים אל RoomDatabase
Builder:
Kotlin
val db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build()
Java
AppDatabase db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build();
למה אי אפשר להשתמש בהפניות לאובייקטים בחדר
נקודות מרכזיות: חדר לא מאפשר הפניות לאובייקטים בין סיווגי ישויות. במקום זאת, לבקש במפורש את הנתונים שדרושים לאפליקציה.
מיפוי קשרים ממסד נתונים למודל האובייקט המתאים הוא ועובד היטב בצד השרת. גם כשהתוכנית נטענת בזמן הגישה אליהם, השרת עדיין פועל היטב.
עם זאת, בצד הלקוח, לא ניתן לבצע טעינה מדורגת מהסוג הזה, היא מתרחשת בדרך כלל ב-thread של ממשק המשתמש, ולבצע שאילתה על מידע על הדיסק בממשק המשתמש thread יוצר בעיות משמעותיות בביצועים. בדרך כלל ה-thread של ממשק המשתמש כולל כ-16 אלפיות השנייה כדי לחשב ולצייר פריסה מעודכנת של פעילות, כך שגם אם לוקח רק 5 אלפיות השנייה, עדיין סביר להניח שייגמר הזמן כדי שהאפליקציה שלך תסתיים משרטטים את המסגרת, באופן שיוצר תקלות חזותיות בולטות. השאילתה יכולה להימשך אפילו נדרשת יותר זמן להשלמת העסקה אם מתבצעת עסקה נפרדת במקביל, או אם במכשיר פועלות משימות אחרות שצורכות הרבה דיסק. אם לא משתמשים אבל האפליקציה מאחזרת יותר נתונים ממה שהיא צריכה, דבר שיוצר זיכרון בעיות צריכה.
מיפויים של קשרים בין אובייקטים בדרך כלל משאירים את ההחלטה הזו למפתחים, הם יכולים לעשות את מה שהכי מתאים לתרחישים לדוגמה של האפליקציה שלהם. בדרך כלל מפתחים מחליטים לשתף את המודל בין האפליקציה שלהם לבין ממשק המשתמש. הפתרון הזה לא עם זאת, מכיוון שממשק המשתמש משתנה עם הזמן, המודל המשותף יוצרת בעיות שקשה למפתחים לחזות ולנפות באגים.
לדוגמה, נבחן ממשק משתמש שטוען רשימה של Book
אובייקטים, עם כל ספר
עם אובייקט Author
. יכול להיות שבשלב הראשון תעצבו את השאילתות
בטעינה כדי שהמופעים של Book
יאחזרו את המחבר. האחזור הראשון של
השדה author
שולח שאילתה למסד הנתונים. זמן מה לאחר מכן אתה מבין
עליך להציג את שם המחבר גם בממשק המשתמש של האפליקציה. יש לך אפשרות לגשת
מספיק בקלות, כפי שמוצג בקטע הקוד הבא:
Kotlin
authorNameTextView.text = book.author.name
Java
authorNameTextView.setText(book.getAuthor().getName());
עם זאת, השינוי הזה לכאורה תמים גורם ליצירת שאילתות לגבי הטבלה Author
בשרשור הראשי.
אם תשאלו מראש את פרטי המחבר/ת, יהיה קשה יותר לשנות אותו
באופן שבו הנתונים נטענים אם אתם לא צריכים יותר את הנתונים האלה. לדוגמה, אם
ממשק המשתמש כבר לא צריך להציג מידע על Author
, האפליקציה נטענת ביעילות
נתונים שכבר לא מוצגים, תוך בזבוז מקום זיכרון יקר. של האפליקציה שלך
היעילות יורדת עוד יותר אם המחלקה Author
מפנה לטבלה אחרת,
כמו Books
.
כדי להפנות לכמה ישויות בו-זמנית באמצעות 'חדר', צריך ליצור בשדה POJO שמכיל כל ישות, כותבים שאילתה שמצרפת את השאילתה בטבלאות. המודל הזה מובנה היטב, שמשלב את השאילתה החזקה של החדר. יכולות אימות מאפשרות לאפליקציה לצרוך פחות משאבים בזמן הטעינה , לשיפור הביצועים של האפליקציה וחוויית המשתמש.