前言

因為自己對 Vue.js 挺熟悉,今次嘗試使用 Android MVVM 寫了一個 app,有些心得,分享一下。


這次的 app 是與一位高手一起合作完成,經過這次經驗,以後也不會想再用 MVVM 架構撰寫 Android,

先講結論


Android MVVM 還需要新增一個 ViewModel 類別,不像 Javascript 可以使用 Model 作為 ViewModel,我認為反而使架構更加複雜。


另外在需要使用到 Context 的時機,我們透過 「模擬 action」方式將事件回傳給 Fragment/Activity,也是更複雜的步驟。


基於以上2點,我們最終決定往後不再使用 Android DataBinding Library。

本文不包含:

MVVM 架構教學


本文包含:

比較 Android 與 Vue.js 中 MVVM 的差異

對於 Android MVVM 的心得

Android MVVM 寫法

Android 透過 ViewModel 類別與 Observable 進行 DataBinding,

同時 XML 也需要有相對應宣告。


我們以「在 Activity 中,將數字顯示到 TextView上」為例,

先看看一般的作法 MainActivity.java & activity_main.xml:

再看看「Data Binding Library」的作法,

建立 MVVMActivityViewModel,進行 DataBinding:

以下要特別注意的地方是「ActivityMvvmBinding」是在 XML layout 中宣告後會自動產生的類別。

如此一來,每次 number(ObservableField<String>)的值變更時,畫面都會自動更新。

Android MVVM 的 Data Binding

我們知道 MVVM 的 View 與 View Model 需要透過 Data Binding 建立連結,

而 Android 中的 View 是 XML Layout,

那麼就需要知道 Android 中的 View Model 是何物,如何進與 View (XML)進行 Data Binding。

我們先以「顯示購物車產品金額小計為例」,探討 MVVM 架構該如何完成:

首先我們的 Model 將會是一個產品,要顯示 Data 的是金額,

那們就必須把金額(Data)連接(Bind)到View上,

而金額一但變動,View就會即時變更。


作法如下:

第一個問題,ViewModel:

由於 Android MVVM 架構中,需要有一個 ViewModel,

那麼 ViewModel 就會依賴於 Model,

反而讓架構更加肥大。

讓我們看看 Vue.js 框架的機制作為比較:

在 View 中,我們在 View(HTML) 中宣告變數,例如: {{totalPrice}},

並可以使用 filters 進行格式處理,例如: {{totalPrice | addThousandsComma}},

ViewModel 完全與 Model 複用。


能夠達成這個結果,最主要的差異在於: javascript 中,我們可以透過 defineProperty,直接改變 Model,

透過新增 getter 與 setter,達到 Data Binding 的目的。

而 Android 無法,因此需要額外多一個 ViewModel 類別。

ViewModel 中使用 Context 的問題

ViewModel 的職責很清楚,在 Android MVVM 架構中,ViewModel 沒有 Context 也是很合理的。

但是一但在進行邏輯操作時需要借助到 Context 時就很麻煩了,有幾個作法,此處討論的做法是讓「ViewModel」回傳事件給 Activity/Fragment。


假設在 app 的運行中,ViewModel 接收到了按鈕事件,需要要求權限(需要 Context),我們透過「MutableLiveData」模擬「action事件回傳」方式,回傳事件給 Activity/Fragment處理。

如此一來,ViewModel 就可以不必擁有 Context,架構更加清晰。

然而,此作法更像是 MVCVM(Model, View, Controller, ViewModel),因為 ViewModel 終究無法脫離 Activity/Fragment。


此處以需要「Context」的時機為例,另外還有像是 「onRequestPermissionsResult」等情境,ViewModel 終究與 Activity/Fragment 密不可分。

FBLINETwitterLinkIn
回部落格