Room 可以完全取代 SQLiteOpenHelper 存取 SQLite 的好物

Room 可以完全取代 SQLiteOpenHelper 存取 SQLite 的好物

有什麼方法可以簡單存取 SQLite,不須撰寫煩人的 SQLiteOpenHelper、ContentProvider 呢?

要寫個有競爭力的 APP 免不了用到資料庫,倘若資料來源為網路(自行開發的 Server Site 、使用別人的 API、Open data …),當網路暢通時 APP 運作正常,若斷線呢?該如何處理離線作業?

寫一份資料到手機上如何?但是光要開個資料庫 (SQLite),又是 SQLiteOpenHelper 、又是ContentProvider、又是Uri 的,好煩哪!於是,不少 persistence 的第三方類別庫因應而生,如 ActiviteAnroid、DBFlow、greenDAO、SugerORM、Realm、Requery 等等族繁不及備載,可見存取 SQLite 資料庫對 Android 工程師是多麼大的負擔 (笑)。

Room

2017 年 5 月,Google I/O ’17 發佈了 Room,至此 persistence 歸於一統 — Room。Room 具有良好的擴充性及彈性,對於多個 Table 間的複合查詢也相當的容易,簡單的標示即可產生Database、Table,對於SQL 語法頭疼的人乃一大福音。

以下用單一 Table 簡單示範導入 Room,及如何使用測試案例,測試我們寫好的標示是否正確。

導入

dependencies {
    :
    :
    implementation "android.arch.persistence.room:runtime:1.0.0"
    annotationProcessor "android.arch.persistence.room:compiler:1.0.0"

    testImplementation "android.arch.persistence.room:testing:1.0.0"
}

標示

Room主要組成有三個部份

  • Database
  • Entity
  • DAO

Entity

接著我們開始標示要寫入資料庫的 Java bean,也就是上述的Entity。

@Entity(tableName = TABLE_EXPENSE)
public class Expense {
    public static final String TABLE_EXPENSE = "expense";

    @PrimaryKey(autoGenerate = true)
    private int uid;
    private String cdate;
    private String item;
    private String info;
    private int price;

    :
    (setter & getter)

}
  • 請注意 :  6-10 行宣告屬性的地方,倘若不是使用標準 Java bean (無 setter、getter),請宣告為 public。
  • 預設 Table 內的欄位名稱即為屬性名稱,可使用 @ColumnInfo(name = “column_name”)重新為Table column命名。

DAO

Room 的 DAO 有幾個標示方法

  • Insert
  • Update
  • Delete
  • Query

Query 的彈性極大、變化也多,有興趣的朋友請參考官網文件。以下的方法可視實際需求自行新增或刪改。

@Dao
public interface ExpenseDao {
    @Query("select * from " + Expense.TABLE_EXPENSE)
    public List<Expense> getAll();

    @Query("select * from " + Expense.TABLE_EXPENSE + " where price >= :price")
    public List<Expense> queryByPrice(int price);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public void insert(Expense expense);

}

Database

最後完成 Database 的標示,如此一來即完成 Room 的導入及標示了。

@Database(entities = {Expense.class}, version = 1)
public abstract class ExpenseDatabase extends RoomDatabase {
   public abstract ExpenseDao expenseDao();
}

完成上述幾個步驟後,怎麼知道標示的內容是正確的呢?很難相信這樣就能寫入資料庫了哩!

Test Case

在實際應用到專案中前,可以寫測試案例,測試上述的寫法是否正確。

在 package (androidTest) 中 new Class,如下圖:

以下不逐行介紹測試案例寫法,請參考官網文件

@RunWith(AndroidJUnit4.class)
public class EntityTest {
    private ExpenseDao expenseDao;
    private ExpenseDatabase expenseDatabase;

    @Before
    public  void createDB(){
        Context context = InstrumentationRegistry.getTargetContext();
        expenseDatabase = Room.inMemoryDatabaseBuilder(context, ExpenseDatabase.class).build();
        expenseDao = expenseDatabase.expenseDao();
    }

    @After
    public void closeDb() throws IOException{
        appDatbase.close();
    }

    @Test
    public void writeAndReadInList() throws Exception{
        Expense expense = new Expense("2017-12-27", "book", "android 8.1", 249);
        expenseDao.insert(expense);
        List<Expense> expenses = expenseDao.getAll();
        assert expenses.get(0).getPrice() == 249;
    }

    @Test
    public void queryByPrice() throws Exception{
        List<Expense> expenses = expenseDao.queryByPrice(200);
        assert expenses.size()>0;
    }
   
    :
    :

}

接下來,只要逐一針對 DAO 內容撰寫測試案例,執行結果是 All tests passed,就可以安心了。

是不是很簡單呢?下一篇將示範如何確認真的寫到手機上了。

版權聲明

本文章版權為郭香宜所有,授權範圍僅限綠豆湯網站使用,除Facebook之類社群等未更改本文章出處之分享行為不在此限,其他個人或公司未經作者同意,不得任意將本文章內容轉載至其他網站,或以任何形式重製,為以免觸犯著作權法,請尊重作者之智慧財產權。

相關文章:

發佈留言

×
×

Cart