Room 為 Android 官方推薦的 ORM 框架,該框架封裝了 SQLite 為底層並提供高層介面以方便使用者快速開發數據儲存。
官方連結:https://developer.android.com/topic/libraries/architecture/room
以下紀錄如何安裝及簡單的使用技巧。
1.加入Room 到你的專案中
1-1.在 Project 的 build.gradle 加入
allprojects { repositories { jcenter() google() } }
1-2.在 Module 的 build.gradle 加入
dependencies { ... def room_version = "1.1.1" implementation "android.arch.persistence.room:runtime:$room_version" annotationProcessor "android.arch.persistence.room:compiler:$room_version" // use kapt for Kotlin ...
2.建立相關元件
2-1.首先建立要儲存的類別(User)
import android.arch.persistence.room.Embedded; import android.arch.persistence.room.Entity; import android.arch.persistence.room.PrimaryKey; @Entity(tableName = "user") public class User { @PrimaryKey private int id; private int listNumber; private boolean active; private String name; private String description; @Embedded private Account account; public int getId() { return id; } public void setId(int id) { this.id = id; } public boolean getActive() { return active; } public void setActive(boolean active) { this.active = active; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public int getListNumber() { return listNumber; } public void setListNumber(int listNumber) { this.listNumber = listNumber; } public Account getAccount() { return account; } public void setAccount(Account account) { this.account = account; } }
注意以下幾點:
第5行使用 @Entity 註解並指定資料表名稱,也可以不指定資料表名稱,預設會使用類別名稱當作資料表名稱。
第8~9行使用 @PrimaryKey 指定主鍵,主鍵為 id
第15~16行自定義類別 Account 必須使用 @Embedded 註明
第18~64行為一般的 getter and setter 方法
自定義類別 Account 如下
import android.arch.persistence.room.ColumnInfo; import android.arch.persistence.room.Entity; import android.arch.persistence.room.PrimaryKey; @Entity(tableName = "account") public class Account { @PrimaryKey @ColumnInfo(name = "account_id") private int id; @ColumnInfo(name = "account_name") private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
注意以下幾點
和 User 類別類似,唯一需要注意的是第 9 行和第 12 行的 @ColumnInfo() 註解。
當某個類別(Account)為另一個類別(User)的嵌入類別時,若欄位名稱有相同必須透過 @ColumnInfo 指定另一個名稱。
以第 9 行 name = “account_id” 為例,就是告訴 Room,Account 的 id 在資料表中欄位名稱為 account_id,避免和 User 的 id 欄位名稱重覆。
2-2.建立DAO(UserDAO)
import android.arch.persistence.room.Dao; import android.arch.persistence.room.Delete; import android.arch.persistence.room.Insert; import android.arch.persistence.room.OnConflictStrategy; import android.arch.persistence.room.Query; import android.arch.persistence.room.Update; import java.util.List; @Dao public interface UserDao { @Query("SELECT * FROM user") public List<User> getAllUser(); @Query("SELECT * FROM user WHERE active = :active") public List<User> getUserActive(boolean active); @Query("SELECT * FROM user WHERE listNumber < :lessNumber") public List<User> getUserListNumberLessThan(int lessNumber); @Insert(onConflict = OnConflictStrategy.REPLACE) public void insertUser(User users); @Insert(onConflict = OnConflictStrategy.REPLACE) public void insertUsers(List<User> users); @Update public void updateUsers(User... users); @Update public void updateUser(User user); @Delete public void deleteUser(User user); @Delete public void deleteUsers(List<User> users); }
UserDAO 即為操作 User 的 Data Access Object,關於 User 的資料庫操作介面全部都會定義在這裡。只需要定義介面就好,Room 會自動實作其內容。
注意以下幾點
第9~10行使用建立 interface 並使用 @Dao 標示
第12~13行使用 @Query 標示該介面為 query 動作並在括號中指定要動作的內容。
Room 提供了4種註解@Query, @Update, @Insert, @Delete 這4種註解分別提供不同的動作,各個動作可以指定的內容請參考 API。
以第12~13行為例,呼叫 getAllUser 就等於 select * from user 代表回傳已儲存的所有 user 內容。
第15~16行代表回傳已儲存的所有 user 內容且 active 欄位必須符合傳入的參數(true or false)。
第18~19行代表回傳已儲存的所有 user 內容且 listnumber 欄位必須小於指定的參數。
第21~22行為插入資料用,而 onConflict = OnConflictStrategy.REPLACE 代表若主鍵發生重複,那就把新的資料取代已儲存的資料。
第24~25行為插入資料用,類似第21~22行。差別在於可以傳入 list。
第27~28行為更新資料用,會根據主鍵以傳入的資料取代已儲存的資料。
第30~31行為更新資料用,類似第27~28行。差別在於可以傳入 list。
第33~34行為刪除資料用,會根據主鍵刪除已儲存的資料。
第36~37行為刪除資料用,類似第33~34行。差別在於可以傳入 list。
2-3.建立一個抽象類別並繼承RoomDatabase
@Database(version = 1, entities = {User.class}) public abstract class RoomDBWrapper extends RoomDatabase { private static RoomDBWrapper sUnique = Room .databaseBuilder(SingletonApplication.getInstance(), RoomDBWrapper.class, "user.db") .allowMainThreadQueries().build(); public static RoomDBWrapper getInstance() { return sUnique; } public abstract UserDao getUserDao(); }
注意以下幾點
1.該類別主要用途為建立資料庫並管理 DAO,可以考慮套用 Singleton Pattern。
2.必須是抽象類別並繼承 RoomDatabase
第1行使用 @Database 註解並指定 version(版本),entities(要儲存類別,如有多個就必須一一加入)
第4行建立 sUnique 變數,之後都透過該變數來取得 DAO 並進行相關操作。
第5行的 SingletonApplication 是自定義類別,繼承 Application 如下
public class SingletonApplication extends Application { private static SingletonApplication sUniqueInstance; public static SingletonApplication getInstance() { return sUniqueInstance; } ...
user.db 為資料庫名稱。
第6行注意 allowMainThreadQueries(),呼叫該方法代表予許操作資料庫的動作進行在 ui thread 上,若沒有呼叫該方法,預設是不能在 ui thread 上操作資料。其實也不建議在 ui thread 上進行資料庫操作,避免 ANR。
第8~10行為提供對外存取 sUnique 的方法。
第12行為要儲存類別的 DAO。
3.使用方式
3-1.Insert 資料
private void insert() { for (int i = 0; i < 10; ++i) { User user = new User(); user.setId(i); user.setListNumber(i); user.setName("name " + i); if (i % 2 == 0) { user.setActive(true); } else { user.setActive(false); } user.setDescription("empty"); Account account = new Account(); account.setId(i); account.setName("name " + i); user.setAccount(account); RoomDBWrapper.getInstance().getUserDao().insertUser(user); } }
第3~16行為建立要 insert 的資料。
第17行即呼叫 RoomDBWrapper 進行實際 insert 的動作。
insert 方法完成後 user 資料表就會有 10 筆 user 資料。
3-2.Query 資料
private void queryAllUsers() { List<User> allUser = RoomDBWrapper.getInstance().getUserDao().getAllUser(); }
3-3.Update資料
private void updateUser5() { User user = new User(); user.setId(5); user.setName("updateUser5"); RoomDBWrapper.getInstance().getUserDao().updateUser(user); } private void updateUsers() { for (int i = 0; i < 10; ++i) { User user = new User(); user.setId(i); user.setName("name " + i + 10); RoomDBWrapper.getInstance().getUserDao().updateUsers(user); } }
第3行當 user.setId(5) 之後,並將該 user 傳入第4行 updateUser(user)方法後,就會取代已儲存資料中主鍵(id)為 5 的項目。
第11行 setId 的參數範圍從 0~9,當呼叫第13行 updateUsers(user) 後,就會取代已儲存資料中主鍵(id)範圍從 0~9 的項目。
3-4. Delete 資料
private void deleteUser2() { User user = new User(); user.setId(2); RoomDBWrapper.getInstance().getUserDao().deleteUser(user); }
第3行指定 setId(2)
第4行呼叫 deleteUser(user),即代表刪除已儲存資料中,主鍵(id)為 2 的項目。
Article Comments