ห้องพักมีฟังก์ชันสำหรับแปลงระหว่างประเภทพื้นฐานและแบบกล่อง แต่ไม่อนุญาตให้มีการอ้างอิงออบเจ็กต์ระหว่างเอนทิตี เอกสารนี้ อธิบายวิธีใช้ตัวแปลงประเภทและเหตุผลที่ห้องไม่รองรับวัตถุ บุคคล
ใช้ตัวแปลงประเภท
บางครั้งคุณอาจต้องการให้แอปจัดเก็บประเภทข้อมูลที่กำหนดเองไว้ในฐานข้อมูลเดียว
คุณรองรับประเภทที่กำหนดเองได้โดยการระบุตัวแปลงประเภท ซึ่งเป็น
ที่บอกห้องถึงวิธีแปลงประเภทที่กำหนดเองเป็นและจากประเภทที่รู้จัก
ห้องแชทจะยังคงเดิม คุณสามารถระบุตัวแปลงประเภทโดยใช้
@TypeConverter
สมมติว่าคุณต้องการคงอินสแตนซ์ของ Date
ไว้ใน
ฐานข้อมูลห้องแชท ห้องแชทไม่ทราบวิธียืนยันออบเจ็กต์ 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(); } }
ตัวอย่างนี้กำหนดวิธีการสำหรับตัวแปลง 2 ประเภท ได้แก่ วิธีที่ใช้แปลง Date
เป็นออบเจ็กต์ Long
และออบเจ็กต์ที่แปลงค่าผกผันจาก
Long
ถึง Date
เนื่องจาก Room รู้วิธียืนยันวัตถุ Long
จึงใช้
ตัวแปลงเหล่านี้เพื่อคงออบเจ็กต์ Date
รายการไว้
ต่อไป ให้เพิ่ม@TypeConverters
เป็นคำอธิบายประกอบในคลาส AppDatabase
เพื่อให้ห้องทราบเกี่ยวกับตัวแปลง
ที่คุณกำหนด:
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(); }
เมื่อกำหนดตัวแปลงประเภทเหล่านี้แล้ว คุณสามารถใช้ประเภทที่กำหนดเองได้ใน เอนทิตีและ DAO เหมือนกับที่คุณใช้ประเภทพื้นฐาน ดังนี้
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); }
ในตัวอย่างนี้ Room จะใช้ตัวแปลงประเภทที่กำหนดไว้ได้ทุกที่เนื่องจากคุณ
ใส่คำอธิบายประกอบ AppDatabase
ด้วย @TypeConverters
อย่างไรก็ตาม คุณอาจประเภท
ผู้แปลงเป็นเอนทิตีหรือ DAO ที่เฉพาะเจาะจงโดยใส่คำอธิบายประกอบใน @Entity
หรือ @Dao
ชั้นเรียนกับ @TypeConverters
การเริ่มต้นตัวแปลงประเภทการควบคุม
โดยปกติแล้ว Room จะจัดการการเริ่มต้นแปลงประเภทให้คุณ อย่างไรก็ตาม
บางครั้งคุณอาจต้องส่งผ่านทรัพยากร Dependency เพิ่มเติมไปยังตัวแปลงประเภท
ซึ่งหมายความว่าคุณต้องใช้แอปเพื่อควบคุมการเริ่มต้นโดยตรง
ของเครื่องแปลงประเภทแล้ว ในกรณีดังกล่าว ให้ใส่คำอธิบายประกอบคลาสตัวแปลงด้วย
@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
เครื่องมือสร้าง:
Kotlin
val db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build()
Java
AppDatabase db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build();
ทำความเข้าใจสาเหตุที่ห้องแชทไม่อนุญาตการอ้างอิงวัตถุ
สิ่งสำคัญที่เรียนรู้: Room ไม่อนุญาตการอ้างอิงออบเจ็กต์ระหว่างคลาสเอนทิตี แต่คุณต้อง ขอข้อมูลที่แอปของคุณต้องการอย่างชัดเจน
การจับคู่ความสัมพันธ์จากฐานข้อมูลกับโมเดลออบเจ็กต์ที่เกี่ยวข้องนั้นเป็น ฝึกฝนและทำงานบนฝั่งเซิร์ฟเวอร์ได้ดี แม้ในขณะที่โปรแกรมโหลดอยู่ เมื่อมีการเข้าถึง เซิร์ฟเวอร์จะยังคงทำงานได้ดี
อย่างไรก็ตาม ในฝั่งไคลเอ็นต์ การโหลดแบบ Lazy Loading ประเภทนี้ทำไม่ได้เนื่องจาก ซึ่งมักจะเกิดขึ้นในเธรด UI และการค้นหาข้อมูลในดิสก์ใน UI ชุดข้อความก่อให้เกิดปัญหาด้านประสิทธิภาพอย่างมีนัยสำคัญ โดยปกติแล้ว เทรด UI จะมี ประมาณ 16 มิลลิวินาที ในการคำนวณและวาดเค้าโครงที่อัปเดตของกิจกรรม ดังนั้นแม้จะมี ใช้เวลาเพียง 5 มิลลิวินาที จึงยังเป็นไปได้ว่าแอปของคุณหมดเวลาเพื่อ วาดเฟรมที่ทำให้เกิดข้อบกพร่องทางสายตาที่สังเกตเห็นได้ การค้นหาอาจใช้เวลาแม้กระทั่ง มีเวลามากขึ้นในการดำเนินการให้เสร็จสมบูรณ์หากมีธุรกรรมแยกต่างหากที่ทำงานพร้อมกัน หรือ หากอุปกรณ์กำลังทำงานอื่นๆ ที่จำเป็นต้องใช้ดิสก์ ถ้าคุณไม่ได้ใช้โหมด Lazy แต่การโหลดแอปกลับดึงข้อมูลมากเกินความต้องการ จึงสร้างหน่วยความจำ ของ Google
การแมปวัตถุแบบสัมพันธ์กันมักจะให้การตัดสินใจนี้แก่นักพัฒนาซอฟต์แวร์เพื่อให้ สามารถทำทุกอย่างที่เหมาะกับกรณีการใช้งานของแอป นักพัฒนาซอฟต์แวร์มักจะ ตัดสินใจแชร์โมเดลระหว่างแอป กับ UI โซลูชันนี้ไม่ แต่ปรับขยายขนาดได้ดี เนื่องจากเมื่อ UI เปลี่ยนแปลงไปตามเวลา โมเดลที่แชร์ สร้างปัญหาที่นักพัฒนาซอฟต์แวร์คาดการณ์และแก้ไขข้อบกพร่องได้ยาก
ตัวอย่างเช่น ลองใช้ UI ที่โหลดรายการออบเจ็กต์ Book
พร้อมหนังสือแต่ละเล่ม
มีออบเจ็กต์ Author
ในตอนแรกคุณอาจออกแบบการค้นหาให้ใช้ Lazy Loading
กำลังโหลดเพื่อให้มีอินสแตนซ์ของ Book
เรียกข้อมูลผู้แต่ง การดึงข้อมูลครั้งแรกของ
ฟิลด์ author
จะค้นหาฐานข้อมูล ในภายหลังคุณจึงตระหนักว่า
ต้องแสดงชื่อผู้เขียนใน UI ของแอปด้วย คุณเข้าถึง
ให้เข้าใจง่าย ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
Kotlin
authorNameTextView.text = book.author.name
Java
authorNameTextView.setText(book.getAuthor().getName());
อย่างไรก็ตาม การเปลี่ยนแปลงที่ดูเหมือนจะไร้เดียงสานี้ทำให้มีการค้นหาตาราง Author
ในเทรดหลัก
หากคุณค้นหาข้อมูลผู้แต่งล่วงหน้า การเปลี่ยนแปลงนั้นอาจทำได้ยาก
วิธีโหลดข้อมูลหากคุณไม่ต้องการข้อมูลนั้นแล้ว ตัวอย่างเช่น หากแอปของคุณ
UI ไม่จำเป็นต้องแสดงข้อมูล Author
อีกต่อไป แอปของคุณโหลดได้อย่างมีประสิทธิภาพ
ข้อมูลที่ไม่แสดงอีกต่อไป ทำให้สูญเสียพื้นที่หน่วยความจำอันมีค่า แอปของคุณ
ประสิทธิภาพจะลดลงไปอีกหากคลาส Author
อ้างอิงตารางอื่น
เช่น Books
หากต้องการอ้างอิงหลายเอนทิตีพร้อมกันโดยใช้ห้องแชท คุณจะต้องสร้าง POJO ที่มีแต่ละเอนทิตี แล้วเขียนข้อความค้นหาที่เชื่อมเอนทิตีที่เกี่ยวข้อง โมเดลที่มีโครงสร้างดีนี้รวมกับการค้นหาที่มีประสิทธิภาพของห้อง ความสามารถในการตรวจสอบความถูกต้องช่วยให้แอปของคุณใช้ทรัพยากรน้อยลงเมื่อโหลด เพื่อปรับปรุงประสิทธิภาพของแอปและประสบการณ์ของผู้ใช้