實作 Android MVVM pattern + LiveData 以 Search Github Repositories 為例
Google 推出包含 LiveData 與 ViewModel 的架構 ,這有助於 Android 開發者使用 MVVM 架構開發 Android 應用程式。首先先來暸解一下何謂 MVVM 架構吧。
註: 此篇暫時不用 Android Data Binding 的方式來實作,並且以 Kotlin 為主要的程式語言
1. MVVM 架構 :
MVVM 架構是 Model-View-ViewModel 的縮寫,架構中有包括三個主要成員,分別是 View,ViewModel,Model。這三個成員分別在 MVVM 架構擔任什麼角色呢? 讓我們看下去...
View :
這個應該不用多做解釋了,Android 中的 Activity / Fragment / View 都是在MVVM 架構下擔任 View 這個角色
ViewModel:
ViewModel 負責接收 View 傳來的任何需求後跟 Model 要求資料,並且把Model 所提供的資料存起來提供給 View 使用。
以這個實作舉例,當使用者在 Android EditText上面輸入想要搜尋的 Github Repository 關鍵字,輸入完成後,按下搜尋按鈕,View 會向 ViewModel 請求取得相關Github repository,這時候,ViewModel 就會去跟 Model 做要求資料的行爲,並將回傳的 Github repository 資料保存給View使用。
Model:
Model 在這邊也可以當作 DataModel,是個負責取得資料的角色,不管是透過 API 或著是本地的儲存空間取得資料都是他的工作範圍
2. Android ViewModel:
ViewModel 是為特定的 UI(例如 Activity/Fragment)提供資料的 Class,同時它也承擔和資料相關的邏輯處理功能。因為 ViewModel 是獨立於View,所以並不會被View的事件影響,比如 Activity 被回收或者是螢幕旋轉等並不會造成 ViewModel 的改變。
當然的,在使用 ViewModel 有許多地方要注意,比如說 ViewModel 的生命週期要比 Views 長,所以不能在 ViewModel 中持有 Views 的 reference,否則會造成 Memory Leak 等問題
在使用 ViewModel 一些要注意的事情可以參考ViewModels and LiveData: Patterns + AntiPatterns這篇文章喔
3. Android LiveData:
LiveData 是一個包含可以被觀察資料的載體。這麼說又有點不好理解?,其實他就是基於觀察者模式去做的。當 LiveData 的資料被更新時,所有對這個LiveData 變化感興趣的 Class 或者是 View 都會收到資料更新的通知。
並且他們之間並沒有類似於 Interface callback 這樣明確的依賴關係。LiveData 還能夠感知 Android 元件(例如 activities / fragments /services)的生命週期,防止 Memory Leak。
其實這和 RxJava 非常相似,但 是 LiveData 能夠在元件生命週期結束後自動切斷資料流的推送,防止產生 NullPointException 等 Exception。這跟 RxJava 是有點不同的。
4. MVVM + LiveData:
以上圖為例,我們將 LiveData 掛載於 ViewModel 中,當 View 向 ViewModel發出請求,這時候 ViewModel 會請 Model 去跟 API 取得資料後更新身上的LiveData。這時候當有對這個 ViewModel 上的 LiveData 做觀察的View就會收到 DataSet 被更新通知,View 就可以取得新的 DataSet 去更新 UI
5. 以Search Github Repository為例:
我們的目標會是以做出下面簡單的頁面為例,當使用者在 Demo app 上方的EditText 輸入想要搜尋的 Github repository 關鍵字,按下 Search 後,回傳相關的 Github repository 關鍵字
註:Call API 的方式是使用 Retrofix 套件
1.定義 Github Service :
這個 Service 是利用 Retrofix 套件定義 search repository 的 interface
定義 Call API 的方式後,建立一個 ServiceManager 來管理它
2.建立 DataModel
其中 OnDataReadyCallback 是用來跟 ViewModel 溝通的橋樑
3.建立 ViewModel
在 ViewModel 會看到 mRepositories 跟 mIsLoading 這兩個 LiveData
其中 mRepositories 是存放跟 Github API 搜尋回來的 repositories 資料,mIsLoading 是用來控制當 View 還在等待資料回來前/後要顯示 Progressbar 的指標
4. 在 MainActivity 初始化 ViewModel
在 MainActivity onCreate 初始化 RepoViewModel (它是一個 ViewModel ),並將 ViewModel 中的 LiveData 設定為觀察對象
5. View 向 ViewModel Search Repository 發出請求
這邊暫時不處理 List 分頁的事宜 (Just for Demo ~^^! 簡單就好)
6.接下來會發生的事情....
View 向 ViewModel 發出 searchRepositories 的需求 ,ViewModel 透過DataModel 去 Call API ,資料回來後,DataModel 透OnDataReadyCallback 將 Repo資料送給 ViewModel。
ViewModel 拿了 DataModel 給予的資料更新身上的 LiveData,這時候LiveData 就會發出資料更新通知給有觀察 LiveData 的 View,然後 View 就將其資訊顯示於UI
6. 感想
ViewModel 與 LiveData 提供 MVVM 方便的架構方式,此架構方式也有利於單元測試。層次分明,使用上蠻清楚明瞭的,架構間的耦合又更低了。值得大家來試試看
所以!我說那個醬汁呢? 醬汁在這裡 (醬汁擺在 GitLab 上)