如果不使用Room、LiveData、ViewModel只使用SqliteOpenHelper會怎樣? 上篇 "查詢"

關於學習Android的資料庫運作,
現在很少直接操作SQLiteOpenHelper
通常會直接學習使用Room和ContentProvider來操作資料,
並配合MMVM架構去撰寫程式碼。

但直接讓新手學這種較多抽象的東西,
如果沒實作過糟糕的方式...恐怕無法真正理解這些做法好在哪?
以及重點差異。

基於上述理由我想用SQLiteOpenHelper實作一個沒有清楚分割UI和Model的案例。

最棒的學習方式是從問題中學習並解決它,
所以我們來假設一個需求「能查看&修改產品清單的App」
(當然只限於Android端)。

產品可視為一個資料表Products,
每一個產品需要有產品名稱、價格、庫存量,最後還需要一個唯一值的ID,總共4個Column要定義。

規劃的架構如下:

Step1 建立一個Contract來管理資料庫、資料表會用到的常量。


將條目定義成常量的好處在於IDE會提供自動補全,
可以避免打錯字這類低階錯誤,

Step2 建立資料類別Product


將每一筆資料都轉成Product物件處理,方便RecyclerView的Adapter處理。

Step3 建立ProductSqlOpenHelper



繼承父類SqliteOpenHelper,並實現類的onCreateonUpgrade
通常onCreate做的就是建立資料表,onUpgrade則是當資料表結構有變動之類的進行更新的函數(當VERSION_NUMBER改變)。

另外我又定義了兩個方法,
查詢資料用的方法getAllProducts

 回傳的結果型態是List<Product>,之後將會提供給Adapter使用。
參數只需要SqliteDatabase,
回傳的結果就是一個Product的List(List<Product>),
之後會提供給Adapter使用。

插入Product用的方法insertProduct
參數包掛db、Product代表要插入Products資料表的資料,
回傳新增item的id,如果新增失敗回傳-1,
因為db.insert會回傳插入item的id,當錯誤發生會回傳-1。

方法內部使用ContentValues以Key-Value的形式將Product插入資料表。


註: 你應該在Cursor用完後關閉,但千萬不要隨便關閉db.close()
最好是在onDestroy呼叫時再進行關閉,
且關閉也最好用Helper的close()而不是database的close()。

Step4 "產品列表"畫面RecyclerView


原本就有的activity_main還會需要再兩個XML ,
一個RecyclerView和一個itemView。

Step5 建立Adapter

Adapter的功用主要是將資料正確填充在列表的每個item。
建構元參數List<Product> products是填充每個item的資料來源。

需要定義好ProductViewHolder和實作三個方法。
onCreateViewHolder()中指定item要填充的layout(此為content_main_item.xml)
getItemCount() 回傳 products的大小。
onBindViewHolder將當前position位置的item資料填入holder中對應的View(此為nameTextViewsummaryTextView)中

Step6 設定MainActivity



定義RecyclerView的Adapter和LayoutManager

layoutManager定義為LinearLayout(也可是GridLayout等等),
沒設定也不報錯算是初學蠻常忘的東西。
adapter的productList是從Sqlite查詢得到的,

管理ProductSqlOpenHelper的生命週期

建立一個myHelper屬性,
onCreate時賦值給它一個ProductSqlOpenHelper。
onDestroy時進行關閉的動作myHelper
結果

下篇 "新增、刪除、修改"

留言

這個網誌中的熱門文章

Kotlin玩Android第03篇 Listview(01 ArrayAdapter)

使用Intent在Activity間傳遞資料(bundle)

golang本地測試如何繞過防火牆詢問允許