採用的架構是 Android 官方所推薦的 MVVM。
Why MVVM?
- 關注點分離(Separation of Concerns)
- View observer ViewModel 裡面的 LiveData,當 LiveData 的值有更新時,View 的畫面就可以主動更新。
- 支援 Data Binding:findViewById 再見了~
- ViewModel 有自己的生命週期,View 重新開啟時,ViewModel 可以保存原有的資料而不需重啟建。
ViewModel 的生命週期
在以前,當裝置旋轉時,Activity 會呼叫 onDestroy 並且重新呼叫 onCreate 一次,所以需要在 onSaveInstanceState() 被呼叫時,將所有的資料存起來,接著在 Activity 被重啟時,就可以拿方才存起來的內容來重新畫畫面。一來是很麻煩,二來是存放的資料是有限制的。所以很多的 App 就不允許旋轉裝置,當然也就不會有這個情況發生了。 從下方的 ViewModel 生命週期圖得知:當 Activity 因裝置旋轉時而造成的 onDestroy → onCreate,ViewModel 的生命週期還是存在,所以存放在 ViewModel 中的資料不需要重建,也就不會有以前的那些問題了。
How to use MVVM?
MVVM 是由 Model, ViewModel 以及 View 三個元素所組成。
View:Activity / Fragment。
Model:上一篇文章中,我們依據 JSON 所產生出來的 Model。
ViewModel:介於 View 與 Model 中間,提供資料給 View 層,以及跟 Model 層取得資料的內容。
心智圖
如前所述, MVVM 包含了 View、 ViewModel 以及 Model。
其中 Model 已經在上一篇文章中已經建好了,我們接著上篇的進度建立 View 以及 ViewModel 。
View
在現代化的 Android 架構中,是由單一 Activity 操縱多個 Fragment ,並且搭配 Navigation 進行 Fragment 的切換。單一 Activity 的概念可以參考影片。
Navigation
Navigation 是由三個部分所組成的,Navigation 圖、NavHost (容器)、NavController (管理NavHost 的物件)
DataBinding
使用 DataBinding,我們就可以減少在 View 上面去更新畫面的動作,可以將這些動作直接搬到 XML 上。
要啟用 data binding 需要在 build.gradle (app)上加上:
plugins {
...
id 'kotlin-kapt'
} android {
...
buildFeatures {
dataBinding true
}
}
ViewModel
將更新 Model 的任務放在 ViewModel 裏面。(將在下一篇文章介紹)
實作流程
1. View
建立 Activity 以及 Fragment,並且使用 Navigation 將頁面串起來
Navigation
Setup navigation dependencies
建立 Navigation graph ( res → command+N (New) → Navigation Resource File)
New Resource File Wizard
輸入 File Name (nav_main)
點選 New Destination
點選 Create new destination 或是 從下方選擇已經建立好的 View
→這邊選擇 Create new destination,並且選擇一個空的 Fragment (Fragment(Blank))
包含一個 Fragment 的 Navigation 就建立好了
fragment_drivers.xml
Activity
建立好 Navigation 之後,我們就可以來設定 Activity 的 layout 了。
activity_main.xml
利用 FragmentContainerView 填滿整個 layout,它是專門被設計當作 Fragment 的容器 (Bye bye FrameLayout)
因為我們是使用 navigation 來串連 Fragment,所以 android:name 需要使用 “androidx.navigation.fragment.NavHostFragment”,並且要在 app:navGraph 中設定剛才建立好的 navigation (@navigation/nav_main)。
MainActivity.kt
在 MainActivity.kt 中,我們將 layout id 填在 AppCompatActivity 的 Constructor 中,就這樣輕鬆的完成 MainActivity 的設置。
Fragment
fragment_drivers.xml
在建立 Navigation graph 時,我們已經建立一個空的 Fragment,在是時候修改它了。
1. 修改 layout,將用 RecyclerView 顯示資料
2. 修改 layout 使其支援 data binding
- 在 layout 外層增加 <layout></layout>
- 小技巧:可以使用 IDE 來自動產生。(Mac: Command + Enter)
3. 建置專案 (Mac: Command + F9)
Build → Make Project
在成功建置後,Android 會自動產生 DataBinding 相關的類別。
DriversFragment.kt
把畫面切回來 Fragment,接下來我們要設置 DataBinding
因為在 fragment_drivers.xml 加上 <data></data> ,所以這個 layout 成為 Data binding 的 view。在這裡我們需要使用 FragmentDriversBinding 來填滿畫面。
其中,FragmentDriversBinding 是自動產生的類別,用來跟 fragment_drivers.xml 連接。
onCreateview
在 onCreateView 中,因為 FragmentDriverBinding 就是 fragment_drivers.xm,只是外面包了一層 <data></dat> 使其變成 data binding 的 view,所以我們只需要回傳它的 root 即可。
onViewCreated
當 View 建立完成之後,Fragment 的生命週期就會走到 onViewCreated,這時,我們需要將 viewLifecycleOwner 傳給 binding 的 lifecycleOwner。
這是代表什麼意思呢?viewLifeCycleOwner 代表我們需要使用的這個 LifeCycle 的類別,在這邊代表的是 FragmentDrivers 這個類別。將 viewLifeCycleOwner 指派給 binding 的 lifecycleOwner 後,這個 layout 的生命週期就跟 Fragment 類別綁在一起了。
小結
上篇文章我們利用 Retrofit 取得資料,本篇文章開始進行 View 的設置,複習一下本篇介紹了什麼吧。
- 使用 Navigation components。
- Navigation components 分為三個部分,Navigation graph, NaviHost, NaviController。這邊目前只使用到 Navigation graph,NaviHost。
- 可以輕鬆的在 IDE 上建立 Navigation graph。如果 Fragment 不存在,也可以直接在 Navigation graph 上加入新的 Fragment。
- 用 Navigation 時, Activity 的 layout 需使用 FragmentContainerView 當作 Fragment 的容器 ,也就是 NavHost 的部分。
- 在需要使用 data binding 的 layout 外圍加上 <data></data> ,建置專案後,該 layout 就會自動產生一個 Binding 的 類別。
- 在該 layout 的實體中,我們可以直接使用 Binding 的類別來取得其 root ,代表這個 layout 的內容。
- 當 View 建立完成之後,我們將 viewLifeCycleOwner 指派給 Binding 類別的 lifeCycleOwner。如此,這個 layout 就會跟 View( Activity/Fragment)的生命週期連接在一起。
本篇文章,我們把 View 的部分建立起來了,並且加上 Data binding,並且使用 Navigation 。接下來的文章,我們將利用 Retrofit 取得的資料,利用 ViewModel 與 Fragment 做連結。當然,因為 Fragment 呈現資料的方式是採用 RecyclerView ,所以我們也會提到如何在 RecyclerView 中使用 data binding。
我們下篇文章見。
如果本篇文章如果有幫助到你
請拍手👏鼓勵我~
你的鼓勵是我的動力
謝謝大家。