
Kamar adalah perpustakaan yang merupakan bagian dari komponen arsitektur Android. Ini memfasilitasi bekerja dengan objek SQLiteDatabase
dalam aplikasi, mengurangi jumlah kode standar dan memeriksa permintaan SQL pada waktu kompilasi.
Sudah memiliki proyek Android yang menggunakan SQLite untuk menyimpan data? Jika demikian, maka Anda dapat memindahkannya ke Kamar. Mari kita lihat bagaimana cara mengambil proyek yang sudah ada dan refactor untuk menggunakan Room dalam 7 langkah sederhana.
TL; DR: perbarui dependensi gradle, buat entitas Anda, DAO dan basis data, ganti panggilan SQLiteDatabase
dengan panggilan metode DAO, uji semua yang Anda buat atau modifikasi, dan hapus kelas yang tidak digunakan. Itu saja!
Dalam aplikasi sampel kami untuk migrasi, kami bekerja dengan objek tipe User
. Kami menggunakan citarasa produk untuk menunjukkan berbagai implementasi tingkat data:
- sqlite - menggunakan
SQLiteOpenHelper
dan antarmuka SQLite tradisional. - room - menggantikan implementasinya dengan Room dan menyediakan migrasi.
Setiap opsi menggunakan lapisan antarmuka pengguna yang sama, yang bekerja dengan kelas UserRepository
berkat pola MVP.
Dalam varian sqlite, Anda akan melihat banyak kode yang sering diduplikasi dan menggunakan database di kelas UsersDbHelper
dan LocalUserDataSource
. Kueri dibuat menggunakan ContentValues
, dan data yang dikembalikan oleh objek Cursor
dibaca kolom demi kolom. Semua kode ini berkontribusi pada munculnya kesalahan implisit. Misalnya, Anda bisa melewatkan menambahkan kolom ke kueri atau salah merakit objek dari database.
Mari kita lihat bagaimana Room meningkatkan kode kita. Awalnya, kami cukup menyalin kelas dari varian sqlite dan secara bertahap mengubahnya.
Langkah 1. Memperbarui dependensi gradle
Ketergantungan untuk Kamar tersedia melalui repositori Google Maven yang baru. Cukup tambahkan ke daftar repositori di file build.gradle
utama Anda:
allprojects { repositories { google() jcenter() } }
Tentukan versi perpustakaan Kamar di file yang sama. Saat ini dalam versi alfa, tetapi tetap ikuti perkembangan untuk pembaruan versi pada halaman pengembang :
ext { roomVersion = '2.1.0-alpha03' }
Di app/build.gradle
tambahkan dependensi untuk Kamar:
dependencies { implementation “android.arch.persistence.room:runtime:$rootProject.roomVersion” annotationProcessor “android.arch.persistence.room:compiler:$rootProject.roomVersion” androidTestImplementation “android.arch.persistence.room:testing:$rootProject.roomVersion” }
Untuk bermigrasi ke Kamar, kita perlu meningkatkan versi database, dan untuk menyimpan data pengguna, kita perlu mengimplementasikan kelas Migrasi . Untuk menguji migrasi , kita perlu mengekspor skema. Untuk melakukan ini, tambahkan kode berikut ke file app/build.gradle
:
android { defaultConfig { ... // used by Room, to test migrations javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } } } // used by Room, to test migrations sourceSets { androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) } ...
Langkah 2. Memperbarui kelas model ke entitas
Kamar membuat tabel untuk setiap kelas bertanda @Entity . Bidang di kelas sesuai dengan kolom dalam tabel. Akibatnya, kelas entitas, sebagai aturan, adalah kelas kecil model yang tidak mengandung logika apa pun. Kelas User
kami mewakili model untuk data dalam basis data. Jadi, mari kita perbarui untuk memberi tahu Room bahwa itu harus membuat tabel berdasarkan kelas ini:
- Beri anotasi kelas dengan
@Entity
dan gunakan properti tableName
untuk menetapkan nama tabel. - Tetapkan kunci utama dengan menambahkan penjelasan
@PrimaryKey
ke bidang yang benar - dalam kasus kami, ini adalah ID pengguna. - Tentukan nama kolom untuk bidang kelas menggunakan anotasi
@ColumnInfo(name = "column_name")
. Anda dapat melewati langkah ini jika bidang Anda sudah dinamai kolom yang harus dinamai. - Jika ada beberapa konstruktor di kelas, tambahkan anotasi
@Ignore
untuk memberi tahu Kamar mana yang akan digunakan dan yang tidak.
@Entity(tableName = "users") public class User { @PrimaryKey @ColumnInfo(name = "userid") private String mId; @ColumnInfo(name = "username") private String mUserName; @ColumnInfo(name = "last_update") private Date mDate; @Ignore public User(String userName) { mId = UUID.randomUUID().toString(); mUserName = userName; mDate = new Date(System.currentTimeMillis()); } public User(String id, String userName, Date date) { this.mId = id; this.mUserName = userName; this.mDate = date; } ... }
Catatan: untuk migrasi yang lancar, perhatikan nama-nama tabel dan kolom dalam implementasi asli dan pastikan Anda mengaturnya dengan benar di @ColumnInfo
dan @ColumnInfo
.
Langkah 3. Membuat Objek Akses Data (DAO)
DAO bertanggung jawab untuk mendefinisikan metode akses database. Dalam implementasi awal proyek SQLite kami, semua kueri basis data dieksekusi di kelas LocalUserDataSource
, tempat kami bekerja dengan objek Cursor
. Di Kamar, kami tidak memerlukan semua kode yang terkait dengan kursor, dan kami hanya dapat mendefinisikan permintaan kami menggunakan anotasi di kelas UserDao
.
Misalnya, ketika menanyakan semua pengguna dari database, Room melakukan semua "kerja keras", dan kami hanya perlu menulis:
@Query(“SELECT * FROM Users”) List<User> getUsers();
Langkah 4. Membuat database
Kami telah mendefinisikan tabel Users
kami dan kueri yang terkait, tetapi kami belum membuat database yang akan menyatukan semua komponen Kamar ini. Untuk melakukan ini, kita perlu mendefinisikan kelas abstrak yang memperluas RoomDatabase
. Kelas ini ditandai @Database
, yang mencantumkan objek yang terkandung dalam database dan DAO yang mengaksesnya. Versi database harus ditingkatkan 1 dibandingkan dengan nilai asli, jadi dalam kasus kami akan 2.
@Database(entities = {User.class}, version = 2) @TypeConverters(DateConverter.class) public abstract class UsersDatabase extends RoomDatabase { private static UsersDatabase INSTANCE; public abstract UserDao userDao();
Karena kami ingin menyimpan data pengguna, kami perlu mengimplementasikan ruang kelas Migration
memberi tahu apa yang harus dilakukan ketika beralih dari versi 1 ke 2. Dalam kasus kami, karena skema basis data tidak berubah, kami hanya menyediakan implementasi kosong:
static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(SupportSQLiteDatabase database) {
Buat objek database di kelas UsersDatabase
dengan mendefinisikan nama database dan migrasi:
database = Room.databaseBuilder(context.getApplicationContext(), UsersDatabase.class, "Sample.db") .addMigrations(MIGRATION_1_2) .build();
Untuk mempelajari lebih lanjut tentang cara menerapkan migrasi basis data dan cara kerjanya di bawah tenda, lihat pos ini .
Langkah 5. Memperbarui repositori untuk menggunakan Room
Kami membuat basis data, tabel pengguna, dan kueri kami, jadi sekarang saatnya menggunakannya. Pada titik ini, kami akan memperbarui kelas LocalUserDataSource
untuk menggunakan metode UserDao
. Untuk melakukan ini, pertama-tama kita perbarui konstruktor: hapus Context
dan tambahkan UserDao
. Tentu saja, setiap kelas yang membuat turunan dari LocalUserDataSource
juga harus diperbarui.
Selanjutnya, kami akan memperbarui metode LocalUserDataSource
yang membuat kueri dengan memanggil metode UserDao
. Misalnya, metode yang meminta semua pengguna sekarang terlihat seperti ini:
public List<User> getUsers() { return mUserDao.getUsers(); }
Dan sekarang saatnya untuk meluncurkan apa yang kami lakukan.
Salah satu fitur terbaik dari Room adalah bahwa jika Anda melakukan operasi database pada utas utama, aplikasi Anda akan macet dengan pesan kesalahan berikut:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
Salah satu cara yang dapat diandalkan untuk memindahkan operasi I / O dari utas utama adalah membuat Runnable
baru yang akan membuat utas baru untuk setiap kueri basis data. Karena kami sudah menggunakan pendekatan ini dalam varian sqlite, tidak ada perubahan yang diperlukan.
Langkah 6. Menguji perangkat
Kami menciptakan kelas-kelas baru - UserDao
dan UsersDatabase
dan mengubah LocalUserDataSource
kami untuk menggunakan database Room. Sekarang kita perlu mengujinya.
Menguji UserDao
Untuk menguji UserDao
, kita perlu membuat kelas uji AndroidJUnit4
. Fitur menakjubkan dari Room adalah kemampuan untuk membuat basis data dalam memori. Ini menghilangkan kebutuhan untuk membersihkan setelah setiap tes.
@Before public void initDb() throws Exception { mDatabase = Room.inMemoryDatabaseBuilder( InstrumentationRegistry.getContext(), UsersDatabase.class) .build(); }
Kita juga perlu memastikan bahwa kita menutup koneksi basis data setelah setiap tes.
@After public void closeDb() throws Exception { mDatabase.close(); }
Misalnya, untuk menguji login pengguna, kami menambahkan pengguna dan kemudian memeriksa untuk melihat apakah kami bisa mendapatkan pengguna itu dari database.
@Test public void insertAndGetUser() {
Menguji penggunaan UserDao di LocalUserDataSource
Memastikan LocalUserDataSource
masih berfungsi dengan benar adalah mudah, karena kami sudah memiliki tes yang menggambarkan perilaku kelas ini. Yang perlu kita lakukan adalah membuat database di memori, mendapatkan objek UserDao
dari itu, dan menggunakannya sebagai parameter untuk konstruktor LocalUserDataSource
.
@Before public void initDb() throws Exception { mDatabase = Room.inMemoryDatabaseBuilder( InstrumentationRegistry.getContext(), UsersDatabase.class) .build(); mDataSource = new LocalUserDataSource(mDatabase.userDao()); }
Sekali lagi, kita perlu memastikan bahwa kita menutup database setelah setiap tes.
Pengujian Migrasi Basis Data
Anda dapat membaca lebih lanjut tentang cara menerapkan tes migrasi database, serta cara kerja MigrationTestHelper
, dalam posting ini .
Anda juga dapat melihat kode dari contoh aplikasi migrasi yang lebih rinci.
Langkah 7. Menghapus semua yang tidak perlu
Hapus semua kelas dan jalur kode yang tidak terpakai yang sekarang diganti oleh fungsionalitas Kamar. Dalam proyek kami, kami hanya perlu menghapus kelas UsersDbHelper
, yang memperpanjang kelas SQLiteOpenHelper
.
Jika Anda memiliki database yang lebih besar dan lebih kompleks, dan Anda ingin secara bertahap beralih ke Kamar, maka kami merekomendasikan posting ini .
Sekarang jumlah kode rawan kesalahan standar telah menurun, permintaan diperiksa pada waktu kompilasi, dan semuanya diuji. Dalam 7 langkah sederhana, kami dapat memigrasi aplikasi yang ada ke Kamar. Anda dapat melihat contoh aplikasi di sini .