Room menyediakan fungsionalitas untuk melakukan konversi antara jenis klasik dan jenis yang dapat ditetapkan pada objek, tetapi tidak memungkinkan referensi objek antar-entity. Dokumen ini menjelaskan cara menggunakan konverter jenis dan alasan mengapa Room tidak mendukung referensi objek.
Menggunakan konverter jenis
Terkadang, aplikasi Anda perlu menyimpan jenis data kustom dalam satu kolom
database. Anda mendukung jenis kustom dengan menyediakan pengonversi jenis, yang merupakan
metode yang memberi tahu Room cara mengonversi jenis kustom ke dan dari jenis umum yang
dapat dipertahankan Room. Anda dapat mengidentifikasi pengonversi jenis menggunakan anotasi
@TypeConverter
.
Misalnya, Anda perlu mempertahankan instance Date
di
database Room. Room tidak tahu cara mempertahankan objek Date
, sehingga Anda perlu
menentukan konverter jenis:
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(); } }
Contoh ini menetapkan dua metode konverter jenis: metode yang mengonversi objek Date
menjadi objek Long
, dan metode lainnya yang melakukan konversi terbalik dari
Long
menjadi Date
. Karena Room tahu cara mempertahankan objek Long
, pengonversi dapat menggunakan
pengonversi ini untuk mempertahankan objek Date
.
Selanjutnya, tambahkan anotasi @TypeConverters
ke class AppDatabase
sehingga Room mengetahui class
pengonversi yang telah Anda tentukan:
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(); }
Dengan konverter jenis yang ditentukan ini, Anda dapat menggunakan jenis kustom di entity dan DAO seperti Anda menggunakan jenis sederhana:
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); }
Dalam contoh ini, Room dapat menggunakan pengonversi jenis yang ditentukan di mana saja karena Anda
menganotasi AppDatabase
dengan @TypeConverters
. Namun, Anda juga dapat mencakup pengonversi jenis
ke entity atau DAO tertentu dengan menganotasi class @Entity
atau @Dao
dengan @TypeConverters
.
Menginisialisasi pengonversi jenis kontrol
Biasanya, Room menangani pembuatan instance pengonversi jenis untuk Anda. Namun,
terkadang Anda mungkin perlu meneruskan dependensi tambahan ke class
konverter jenis, yang berarti Anda memerlukan aplikasi untuk mengontrol inisialisasi
konverter jenis secara langsung. Dalam hal ini, anotasikan class pengonversi dengan
@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) { ... } }
Kemudian, selain mendeklarasikan class pengonversi di @TypeConverters
, gunakan
metode RoomDatabase.Builder.addTypeConverter()
untuk meneruskan instance class pengonversi ke builder RoomDatabase
:
Kotlin
val db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build()
Java
AppDatabase db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build();
Memahami mengapa Room tidak mengizinkan referensi objek
Poin utama: Room tidak mengizinkan referensi objek antar-class entity. Sebagai gantinya, Anda harus secara eksplisit meminta data yang dibutuhkan oleh aplikasi Anda.
Memetakan hubungan dari database ke masing-masing model objek adalah praktik yang umum dilakukan dan bekerja dengan sangat baik di sisi server. Bahkan, saat program memuat kolom ketika sedang diakses, performa server akan tetap baik.
Namun, di sisi klien, jenis pemuatan lambat ini akan menyulitkan karena biasanya akan terjadi di UI thread, dan meminta informasi tentang disk di UI thread akan menimbulkan masalah performa yang signifikan. UI thread biasanya membutuhkan waktu sekitar 16 milidetik untuk menghitung dan menggambar tata letak aktivitas yang diperbarui. Jadi, meskipun kueri hanya memerlukan waktu 5 milidetik, aplikasi Anda kemungkinan akan kehabisan waktu untuk menggambar frame sehingga gangguan visual yang cukup terlihat akan muncul. Kueri dapat memerlukan lebih banyak waktu untuk diselesaikan jika ada transaksi terpisah yang berjalan secara paralel, atau jika perangkat sedang menjalankan tugas lain yang membutuhkan banyak disk. Namun, jika Anda tidak menggunakan pemuatan lambat, aplikasi akan mengambil lebih banyak data daripada yang dibutuhkan sehingga akan timbul masalah pada penggunaan memori.
Pemetaan terkait objek biasanya menyerahkan keputusan ini kepada developer agar mereka dapat melakukan yang terbaik sesuai kasus penggunaan aplikasinya. Developer biasanya memutuskan untuk menggunakan model yang sama antara aplikasi mereka dan UI-nya. Namun, solusi ini kurang sesuai karena seiring dengan berubahnya UI dari waktu ke waktu, model bersama akan menimbulkan masalah yang sulit diantisipasi dan di-debug oleh developer.
Misalnya, terdapat UI yang memuat daftar objek Book
, yang masing-masing
memiliki objek Author
. Awalnya, Anda mungkin mendesain kueri untuk menggunakan pemuatan
lambat agar instance Book
mengambil penulisnya. Pengambilan pertama
kolom author
akan membuat kueri pada database. Beberapa waktu kemudian, Anda menyadari bahwa
nama penulis juga perlu ditampilkan dalam UI aplikasi. Anda dapat mengakses nama
ini dengan mudah, seperti dalam cuplikan kode berikut:
Kotlin
authorNameTextView.text = book.author.name
Java
authorNameTextView.setText(book.getAuthor().getName());
Namun, perubahan yang tampaknya tidak berbahaya ini menyebabkan tabel Author
dikueri
pada thread utama.
Jika Anda meminta informasi penulis lebih awal, akan sulit untuk mengubah
cara data dimuat ketika Anda tidak lagi membutuhkannya. Misalnya, jika UI
aplikasi Anda tidak perlu lagi menampilkan informasi Author
, aplikasi Anda akan secara efektif memuat
data yang tidak lagi ditampilkan, dan menghabiskan ruang memori yang berharga. Efisiensi
aplikasi Anda akan terus turun jika class Author
merujuk ke tabel lain, seperti
Books
.
Untuk mereferensikan beberapa entity sekaligus menggunakan Room, Anda dapat membuat POJO yang berisi setiap entity, lalu menulis kueri yang menggabungkan tabel terkait. Model yang terstruktur dengan baik ini, bersama kemampuan validasi kueri Room yang canggih, memungkinkan aplikasi Anda menggunakan lebih sedikit resource saat memuat data sehingga performa aplikasi dan pengalaman pengguna pun akan meningkat.