https://mp.weixin.qq.com/s?__biz=MzA3MjA4NjE3NQ==&mid=404502568&idx=1&sn=fe512f9820b99d3cc8212e363ff57195&scene=1&srcid=0407PIdwHgMcWOBI7P2zEgCa&key=b28b03434249256bd8382e5caf525bcb36d6b31e18f2e933d895b3f91b6a6e10a1d42d613b275625f39a121137975d80&ascene=0&uin=Mjc3OTU3Nzk1&devicetype=iMac+MacBookPro10%2C1+OSX+OSX+10.10.5+build%2814F27%29&version=11020201&pass_ticket=%2F8olw2Mg3%2BO3Hdredp8Koo4%2FdLP647sSn5SKAT3uD06Nfhyo6Peebt0qCKuYnh6O前端
DuangDuangDuangDuang!在今天的乾貨分享開始以前,請容稀土君先插播一條廣告:android
Coding 技術小館第二站北京的活動,掘金 CEO 也是前端負責人陰明會作一場關於 Vue.js 組件化的分享,同時其餘的嘉賓有:Coding 前端高級工程師劉輝分享《Redux 與 React 服務器端渲染》、AWS 解決方案架構師趙霏《用 Javascript 玩轉雲計算》、野狗聯合創始人肖光宇分享《Web 前端的實時化》。服務器
是的,你沒看錯,就是咱們明明能夠靠臉吃飯卻恰恰要用實力說話的陰明大大也會上臺分享哦。他將作的是關於一個輕量級 MVVM 框架 Vue.js 組件化內容的分享,爲了防止有些同窗還不知道 MVVM 是什麼,本期咱們特別準備了這篇關於 MVVM 模式的介紹,但願能幫助到你哦。微信
仍是快點看文章吧。👇架構
-------------------app
我考察了一段時間安卓的數據綁定類庫,決定嘗試下它的「Model-View-ViewModel」模式。由於我曾經和 @matto1990 合做開發過一款應用 HackerNews Reader,因此我決定利用這種模式從新實現它。框架
這篇文章經過一款簡單的 app 來論證 MVVM 模式,我建議你先看看這個項目,讓你大概瞭解下它。組件化
什麼是 MVVM 模式?佈局
Model-View-ViewModel 就是將其中的 View 的狀態和行爲抽象化,讓咱們能夠將 UI 和業務邏輯分開。固然這些工做 ViewModel 已經幫咱們作了,它能夠取出 Model 的數據同時幫忙處理 View 中因爲須要展現內容而涉及的業務邏輯。post
MVVM模式是經過如下三個核心組件組成,每一個都有它本身獨特的角色:
Model-包含了業務和驗證邏輯的數據模型
View-定義屏幕中 View 的結構,佈局和外觀
ViewModel-扮演「View」和「Model」之間的使者,幫忙處理 View 的所有業務邏輯
那這和咱們曾經用過的 MVC 模式有什麼不一樣呢?如下是 MVC 的結構
View 在 Controller 的頂端,而 Model 在 Controller 的底部
Controller 須要同時關注 View 和 Model
View 只能知道 Model 的存在而且能在 Model 的值變動時收到通知
MVVM 模式和 MVC 有些相似,但有如下不一樣:
ViewModel 替換了 Controller,在 UI 層之下
ViewModel 向 View 暴露它所須要的數據和指令對象
ViewModel 接收來自 Model 的數據
你能夠看到這兩種模式有着類似的結構,但新加入的 ViewModel 是用不一樣的方法將組件們聯繫起來的,它是雙向的,而 MVC 只能單向鏈接。
歸納起來,MVVM 是由 MVC 發展而來-經過在 Model 之上而在 View 之下增長一個非視覺的組件未來自 Model 的數據映射到 View 中。接下來,咱們將更多地看到 MVVM 的這種特性。
THE HACKER NEWS READER
正如前面說起過的,我將我原來的一個項目拆開爲這篇文章服務。這款應用有如下幾種特性:
查看帖子列表
查看單個帖子
查看帖子下的評論
查看指定做者的帖子
下面的圖片能讓你很快了解它是怎麼工做的:
左邊的圖片展現的是帖子的列表,它也是這款應用的主要部分,接下來右邊的圖片展現的是該帖子的評論列表,它和前者有類似的地方,但也有一些不一樣,咱們將在後面看到。
展現帖子
每一個帖子信息都用 RecyclerView 所包含的 CardView 包裝起來,正如上圖展現的。
使用 MVVM 咱們能夠將不一樣層抽象出來很好的實現這些卡片,這意味着每一個 MVVM 組件只要處理它被分配的任務便可。經過使用前面介紹的 MVVM 的不一樣組件,組合在一塊兒後能構造出咱們的帖子卡片實例,那麼咱們該如何將它們從佈局中抽離出來?
MODEL
簡單來講,Model 由那些帖子的業務邏輯組成,包括一些像 id,name,text 之類的屬性,如下代碼展現了該類的部分代碼:
爲了可讀性,上面的 POST 類中去掉了一些 Parcelable 變量和方法
這裏你能夠看到 Post 類只包含全部它的屬性,沒有一點別的邏輯 - 別的組件會處理它們。
View
View 的任務是定義佈局,外觀和結構。View 最好能徹底經過 XML 來定義,即便它包含些許 Java 代碼也不該該有業務邏輯部分,
View 會經過綁定從 ViewModel 中取出數據。在運行時,若 ViewModel 的屬性的值有變化的話它會通知 View 來更新UI。
首先,咱們先給 RecyclerView 傳入一個自定義的適配器。爲此,咱們須要讓咱們的 BindingHolder 類持有對 Binding 的引用。
onBindViewHolder() 方法纔是真正將 ViewModel 和 View 綁定的地方。咱們獲取一個 ItemPostBinding 對象(它會被 item_post 佈局自動生成),而後將新建的 PostViewModel 對象傳給它的 ViewModel 引用。
下面就是完整的 PostAdaper 類:
看下咱們的XML佈局,首先咱們要將全部的佈局都包含在layout標籤下,同時使用data標籤來聲明咱們的 ViewModel:
聲明 ViewModel 可讓咱們在整個佈局中引用它,在 item_post 佈局中咱們會屢次用到 ViewModel:
androidText-你能夠從 ViewModel 中引用相應的方法給文本視圖設置內容。正以下面你所看到的 @{viewModel.postTitle},它從 ViewModel 中引用了 getPostTitle() 方法-它將返回相應帖子的標題。
onClick-咱們也能夠引用單擊事件到佈局文件中。如你所看到的,@{viewModel.onClickPost} 是指從 ViewModel 中引用 onClickPost() 方法-它將返回一個能處理單擊事件的 OnClickListener 對象。
visibility - 控制去 comments activity 的入口,依賴於該帖子是否有相應的評論。經過檢查 comments list 的長度來決定該 visibility 的值,這些操做都是在 ViewModel 中完成的。在這裏,咱們引用了它的 getCommentsVisiblity() 方法來計算是否該顯示
這樣作實在太棒了,咱們能抽象出顯示邏輯到咱們的佈局文件中,讓咱們的 ViewModel 來關注它們。
VIEWMODEL
ViewModel 扮演了 View 和 Model 之間使者的角色,讓它來關注全部涉及到 View 的業務邏輯,同時它能夠訪問 Model 的方法和屬性,這些最終會做用到 View 中。經過 ViewModel,能夠移除本來須要在別的組件中返回或處理的數據。
在這裏,PostViewModel 用 Post 對象來處理 CardView 須要顯示的內容,在下面的類中,你能夠看到一系列的方法,每一個方法對最終做用於咱們的帖子視圖。
getPostTitle()-經過 Post 對象返回一個帖子的標題
getPostAuthor()-這個方法首先會從應用的resources中獲取相應的字符串,而後傳入Post對象的author屬性對它進行格式化,若是isUserPosts 等於true咱們就須要加入下劃線,最終返回該字符串。
getCommentsVisibility()-該方法決定是否顯示有關評論的TextView onClickPost()-該方法返回相應View須要的OnClickListener
這些例子代表不一樣的業務邏輯都有咱們的 ViewModel 來處理。下面就是咱們 PostViewModel 類的完整代碼以及那些被item_post佈局引用的方法。
是否是很爽?正如你看到的,咱們的 PostViewModel 關注如下方面:
維護 Post 對象的屬性,最終會在 View 中展現
對這些屬性進行相應的格式化
經過 onclick 屬性給相應的views對提供點擊事件的支持
經過 Post 對象的屬性處理相關 views 的顯示
測試 VIEWMODEL
使用 MVVM 的一大好處是咱們能夠很容易對 ViewModel 進行單元測試。在 PostViewModel 中,能夠寫些簡單的測試方法來驗證咱們的 ViewModel 是否正確實現。
shouldGetPostScore()-測試getPostScore()方法,確認該帖子的得分是否正確地格式化成字符串對象並返回。
shouldGetPostTitle()-測試getPostTitle()方法,確認該帖子的標題被正確返回。
shouldGetPostAuthor()-測試getPostAuthor()方法,確認返回的帖子的做者被正確地格式化了
shouldGetCommentsVisiblity()-測試getCommentsVisibility()方法是否正確返回了visibility屬性的值,它將會用在帖子的 Comments 按鈕中。咱們傳入一個包含不一樣狀態的ArrayLists來確認它是否能正確返回。
如今咱們能夠知道的 ViewModel 已經正確工做了!!
評論
實現評論的方法和前面很像但仍是有點不一樣。
有兩個不一樣的 ViewModel 被用來操做此次評論, CommentHeaderViewModel 和 CommentViewModel。正如你在CommentAdapter中看到的,咱們的 View 有兩種的不一樣類型:
private static final int VIEW_TYPE_COMMENT = 0;
private static final int VIEW_TYPE_HEADER = 1;
若是該帖子是一個發問的帖子,咱們將在屏幕的頂端顯示一個頭部,它顯示所問的問題-接着評論會正常顯示在下面。同時你應該會注意到在 onCreateViewHolder() 中咱們會經過判斷 VIEW_TYPE 來加載不一樣的佈局,它會返回兩種不一樣佈局中的其中一種。
接着在咱們的 onBindViewHolder() 方法中咱們會根據不一樣的視圖類型來建立綁定。這是由於不一樣的 ViewModel 對頭部有不一樣的處理方法
這就是它們的不一樣點,評論部分有兩個不一樣的 ViewModel 類型 — 取決於該帖子是不是發問類的帖子。
總結
若是正確使用,數據綁定類庫可能會改變咱們開發應用的方式。固然,還有其餘方法實現數據的綁定,使用 MVVM 模式只是其中的一種途徑。
好比,你能夠在佈局中引用咱們的 Model 而後經過它的變量引用直接訪問它的屬性:
同時咱們能夠很容易從adapers和classes中移除一些基礎的顯示邏輯。下面有種很新穎的方法實現咱們這種需求:
這就是我看到上面實現方式的表情!
我認爲這是數據綁定類庫中很差的地方,它將 View 的顯示邏輯包含到了 View 中。不只會形成混亂,也讓咱們的測試和調試變的更加困難,由於它將邏輯和佈局混淆在一塊兒。
固然,認定MVVM是開發應用的正確方式還爲時過早,但此次嘗試也讓我有機會見識到將來項目的一種趨勢。若是你想閱讀更多有關數據綁定類庫的文章,你能夠看這裏。同時微軟也有一篇關於MVVM通俗易懂的文章。
我很願意聽取大家想法,若是大家有任何的見解和建議能夠隨時發 Tweet 和我討論!
因爲微信公衆對於外鏈還有文章字數的諸多限制,文中代碼部分以圖片呈現,會出現不完整的狀況。你能夠在稀土圈微信公衆號窗口回覆「MVVM」獲取譯文地址,前往掘金社區閱讀。
怎麼樣,看完文章是否是有所收穫了呢?若是你還想獲取更多更有意思的乾貨,不如點擊文章左下角的「閱讀原文」按鈕,報名本月十號在北京舉辦的 Coding 線下前端分享活動吧。