android UI設計MVVM設計模式討論?
因為google 剛出了一套databinding 框架來實現VM, 一些業務邏輯操作完全可以放入VM來做,還有一些邏輯操作與當前Context有關,可以通過介面實現讓activity 或者fragment來做,如果一個VM來做所有的操作,是不是代碼太多,還是按邏輯拆分幾個不同VM來做?
很不錯的問題。
今天早上跟群里的朋友們討論了一下MVVM,其中@肥肥魚慎重的表示沒有百分百把握不敢教壞小朋友。這幫人都這麼謙虛,那隻能我拋磚引玉了。
在傳統的框架中,提的最多的是MVC和MVP。其中MVC出現與上世紀70年代,在三十多年的工程實踐中,MVC充分證明了它的成功,同時在漫長的時間中演變出了許多變種,其中也包括MVP.MVC和MVP最大的差別在與控制層對於整個框架的控制力上。Android中經常會出現數千行的Activity代碼,究其原因,我認為是Android中純粹作為View的各個XML視圖功能太弱,Activity基本上都是View和Controller的合體,既要負責視圖的顯示又要加入控制邏輯,承擔的功能過多,代碼量大也就不足為奇。所以我認為在Android上,MVP優於MVC,是因為我們需要更強力的控制層最大程度上分擔Activity中邏輯的部分,具體的思想可以參考我的博客:Android App整體架構設計的思考(一)
MVVM可以算是MVP的升級版,其中的VM是ViewModel的縮寫,ViewModel可以理解成是View的數據模型和Presenter的合體,ViewModel和View之間的交互通過Data Binding完成,而Data Binding可以實現雙向的交互,這就使得視圖和控制層之間的耦合程度進一步降低,關注點分離更為徹底,同時減輕了Activity的壓力,三者之間的差別如下如所示:回到題主的問題,VM中View的數據模型每個頁面當然只有一套,但是Presenter,我建議根據邏輯拆開。(剩下的等我周末體驗一下再更新)相關參考:Data Binding Guide對MVC、MVP、MVVM的理解Data Binding 用戶指南(Android)首先對 Google 在 Android 中引入了 Data Binding 的舉措表示點贊,在 Support 包中也出現了使用 MVP 的例子,請翻看 NavigationView 的源碼。
MVC -&> MVP -&> MVVM 這幾個軟體設計模式是一步步演化發展的,MVVM 是從 MVP 的進一步發展與規範,MVP 隔離了 M 與 V 的直接聯繫後,靠 Presenter 來中轉,所以使用 MVP 時 P 是直接調用 View 的介面來實現對視圖的操作的,這個 View 介面的東西一般來說是 showData、showLoading...M 與 V是隔離了,方便測試了,但代碼還不夠優雅簡潔啊,所以 MVVM 就彌補了這些缺陷。在 MVVM 中就出現的 Data Binding 這個概念,意思就是 View 介面的 showData 這些實現方法可以不寫了,通過 Binding 來實現。。
在 Android 中,我個人也是把 Activity、Fragment 當做 View 層的東西的,題主所說 」一些邏輯操作與當前Context有關「,除了彈 Dialog(而且這也是 View),其它情況基本可以自己重寫 Application 來拿 ApplicationContext,那麼題主所說的邏輯操作可以不在 Activity、Fragment 出現吧。VM 也是 M 與 V 的橋樑啊,怎麼會有很多操作呢~一般場景下一個 View 就會有一個相應的 VM。
最後分享一個網站,https://speakerdeck.com (Speakerdeck of GitHub Inc - 在線簡報、PDF分享展示平台!)以及下面的兩個與題目相關的PPT。
Clean Android Architecture:https://speakerdeck.com/richk/clean-android-architecture(這裡有 Coursera App Architecture 的設計分析哦,很贊,翻找 Video 中... ,Demo App 的 Github 傳送門:richk/CourseraDemoApp · GitHub)How to use MVVM pattern in Android (Droidcon Krakow 2014):https://speakerdeck.com/radzio/how-to-use-mvvm-pattern-in-android-droidcon-krakow-2014Last:Architecting Android…The clean way?(自行搜索譯文)=================== Update ====================
寫了篇相關博客:MVVM_Android-CleanArchitecture 代碼:https://github.com/zhengxiaopeng/MVVM_Android-CleanArchitecture關於Android MVVM 最近項目開發中一直在用,從DataBinding發布之後一直在關注,如今DataBinding 正式版終於發布了(相信可能又會掀起Android MVVM的一場熱潮)鑒於之前的一段MVVM的實踐開發經驗,這邊來回答 題主可能t的2個問題:
1、一些業務邏輯操作完全可以放入VM來做,還有一些邏輯操作與當前Context有關,可以通過介面實現讓activity 或者fragment來做?
是否讓一些邏輯操作通過介面讓activity 或者fragment來做這個問題,主要是看你所謂的邏輯操作是什麼,在MVVM 設計框架的時候,我個人是傾向把各層職責分得比較開,每一層只做自己的事情。下面看下我個人理解的每一層的職責和分工。
- View View層做的就是和UI相關的工作,我們只在XML和Activity或Fragment寫View層的代碼,View層不做和業務相關的事,也就是我們的Activity 不寫和業務邏輯相關代碼,也不寫需要根據業務邏輯來更新UI的代碼,因為更新UI通過Binding實現,更新UI在ViewModel裡面做(更新綁定的數據源即可),Activity 要做的事就是初始化一些控制項(如控制項的顏色,添加 RecyclerView 的分割線),Activity可以更新UI,但是更新的UI必須和業務邏輯和數據是沒有關係的,只是單純的根據點擊或者滑動等事件更新UI(如 根據滑動顏色漸變、根據點擊隱藏等單純UI邏輯),Activity(View層)是可以處理UI事件,但是處理的只是處理UI自己的事情,View層只處理View層的事。簡單的說:View層不做任何業務邏輯、不涉及操作數據、不處理數據、UI和數據嚴格的分開。
- ViewModelViewModel層做的事情剛好和View層相反,ViewModel 只做和業務邏輯和業務數據相關的事,不做任何和UI、控制項相關的事,ViewModel 層不會持有任何控制項的引用,更不會在ViewModel中通過UI控制項的引用去做更新UI的事情。ViewModel就是專註於業務的邏輯處理,操作的也都是對數據進行操作,這些個數據源綁定在相應的控制項上會自動去更改UI,開發者不需要關心更新UI的事情。關於對UI控制項事件的處理,我們也希望能把這些事件處理綁定到控制項上,並把這些事件統一化,方便ViewModel對事件的處理和代碼的美觀。為此我們通過BindingAdapter 對一些常用的事件做了封裝,把一個個事件封裝成一個個Command,對於每個事件我們用一個ReplyCommand&
去處理就行了,ReplyCommand& 會把可能你需要的數據帶給你,這使得我們處理事件的時候也只關心處理數據就行了,再強調一遍ViewModel 不做和UI相關的事。 - Model Model 的職責很簡單,基本就是實體模型(Bean)同時包括Retrofit 的Service ,ViewModel 可以根據Model 獲取一個Bean的Observable&
( RxJava ),然後做一些數據轉換操作和映射到ViewModel 中的一些欄位,最後把這些欄位綁定到View層上。 上面三部分的分工很明確,要不要把一部分邏輯放到activity 或者fragment來做是取決於你的提到的操作邏輯是什麼,如果這些邏輯操作是可以通過修改數據(這些數據綁定到UI)來更改UI或者你的操作邏輯是業務邏輯或者修改數據,那麼這塊邏輯你完全可以在ViewModel 裡面做。如果這些邏輯操作只是和UI有關,而且不能通過Binding的方式更改數據源去反饋到UI(比如說 簡單的對話框、PopupWindow等)是可以考慮放到View層去做,但是如果這部分操作邏輯涉及到業務和數據相關的,那麼建議不用放到View層做,View層主要職責是和UI相關的、沒有數據,沒有業務。
2、如果一個VM來做所有的操作,是不是代碼太多,還是按邏輯拆分幾個不同VM來做?
這個問題先看下下面的這張圖:上圖反應了MVVM框架中各個模塊的聯繫和數據流的走向,我們別的模塊先不管,我們直接來看我們的ViewModel模塊,在ViewModel類我傾向於只包含下面5中類型的數據和欄位:1、Context (上下文)
2、Model (數據模型Bean)
3、Data Field (數據綁定)
4、Command (命令綁定)
5、Child ViewModel (子ViewModel)
至於為什麼推薦只包含這5種類型的數據欄位和這些數據欄位分別是做什麼用的,請查看我最新的一盤關於博客:如何構建Android MVVM應用程序,接下來說重點:看到第5條沒有(子ViewModel)
- Child ViewModel (子ViewModel)
子ViewModel 的概念就是在ViewModel 裡面嵌套其他的ViewModel,這種場景還是很常見的。比如說你一個Activity裡面有兩個Fragment,ViewModel 是以業務劃分的,兩個Fragment做的業務不一樣,自然是由兩個ViewModel來處理,Activity 本身可能就有個ViewModel 來做它自己的業務,這時候Activity的這個ViewModel裡面可能包含了兩個Fragment分別的ViewModel。這就是嵌套的子ViewModel。還有另外一種就是對於AdapterView 如ListView RecyclerView,ViewPager等。
//Child ViewModel
public final ObservableList&itemViewModel = new ObservableArrayList&<&>();
它們的每個Item 其實就對應於一個ViewModel,然後在當前的ViewModel 通過ObservableList&
持有引用(如上述代碼),這也是很常見的嵌套的子ViewModel。我們其實還建議,如果一個頁面業務非常複雜,不要把所有邏輯都寫在一個ViewModel,可以把頁面做業務劃分,把不同的業務放到不同的ViewModel,然後整合到一個總的ViewModel,這樣做起來可以使我們的代碼業務清晰,簡短意賅,也方便後人的維護。
所以我們是推薦按業務邏輯拆分幾個不同VM來做,而不僅僅是代碼多不多的才做(業務迭代過程中你能保證你們的PM會讓這個頁面的代碼少嗎?)
最後推薦今天剛整理出來的一個篇關於Android MVVM的博客 如何構建Android MVVM應用程序 以上的內容均出自這篇博文,一些內容是自己個人的理解和總結,如有不對的地方歡迎留言,共同探討。@M.A.G.I 已經說的很好拉,我來補充一些自己的看法吧~
事實上 Activity、Fragment 太「重」是促使 MVP、MVVM 開發框架出現的一個原因,那其他原因是啥呢?不妨看看 Google 推薦所有開發者參考的開發模板 App —— IOsched(應該沒打錯……),IOsched 中的代碼架構就是當時 Google 認為最值得我們參照的開發模板,然而這種開發架構並沒有什麼軟用……為啥呢?
1、例如 IOsched 中一個很簡單很簡單的功能:點擊 + 號按鈕添加 Google IO 到手機的日曆中,我們現在要為它實現測試單元。然後你一番折騰,整個人都快要爆炸了,測試單元還是沒能弄出來。為啥呢?是功夫不到家嗎?某種程度上你可以這樣覺得,但這個鍋並不能給你。根源在於,很多情況下你要在 Android 的 Activity、Fragment 這些類里實現測試單元是不可能的,因為你無法滿足進行單元測試的三個條件。
2、除此以外,雖然 Google 極力推薦我們使用 Fragment,但是 Fragment 一點也不好用,Fragment 的蛋疼之處就在於它那複雜的一B的生命周期。NB 如 Square 都只能憤怒地棄用 Fragment,自己弄了一套框架替代 Fragment。
以上兩點我在博客都有相關的博文哈
追風箏的吃貨,汪~MVVM是非常好的一套設計模式,看了問題才知道Android也引入了這個模式,回家了看一下。之前一直用WPF和MVVM。業務邏輯放在Model中,VM負責調用Model,所以不用擔心VM會太大。
今年的Google IO 大會上,Android 團隊發布了一個數據綁定框架(Data Binding Library)。以後可以直接在 layout 布局 xml 文件中綁定數據了,無需再 findViewById 然後手工設置數據了。其語法和使用方式和 JSP 中的 EL 表達式非常類似。下面就來介紹怎麼使用Data Binding Library。
配置環境
目前,最新版的Android Studio已經內置了該框架的支持,配置起來也很簡單,只需要編輯app目錄下的build.gradle文件,添加下面的內容就好了
android {
....
dataBinding {
enabled = true
}
}
Data Binding Layout文件
Data Binding layout文件有點不同的是:起始根標籤是 layout,接下來一個 data 元素以及一個 view 的根元素。這個 view 元素就是你沒有使用Data Binding的layout文件的根元素。舉例說明如下:
&
http://schemas.android.com/apk/res/android">
&
&
&
&
&
&
&
&
上面定義了一個com.example.User類型的變數user,然後接著android:text="@{user.firstName}"把變數user的firstName屬性的值和TextView的text屬性綁定起來。
Data Object
我們來看下上面用到的com.example.User對象。
public class User {
public final String firstName;
public final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
他有兩個public的屬性firstName,lastName,這和上面layout文件裡面的@{user.firstName}和@{user.lastName}對應
或者下面這種形式的對象也是支持的。public class User {
private final String firstName;
private final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// getXXX形式
public String getFirstName() {
return this.firstName;
}
// 或者屬性名和方法名相同
public String lastName() {
return this.lastName;
}
}
綁定數據
添加完&標籤後,Android Studio就會根據xml的文件名自動生成一個繼承ViewDataBinding的類。例如: activity_main.xml就會生成ActivityMainBinding, 然後我們在Activity裡面添加如下代碼:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
User user = new User("Test", "User");
binding.setUser(user);
}
綁定事件
就像你可以在xml文件裡面使用屬性android:onClick綁定Activity裡面的一個方法一樣,Data Binding Library擴展了更多的事件可以用來綁定方法,比如View.OnLongClickListener有個方法onLongClick(), 你就可以使用android:onLongClick屬性來綁定一個方法,需要注意的是綁定的方法的簽名必須和該屬性原本對應的方法的簽名完全一樣,否則編譯階段會報錯。
下面舉例來說明具體怎麼使用,先看用來綁定事件的類:
public class MyHandlers {
public void onClickButton(View view) { ... }
public void afterFirstNameChanged(Editable s) { ... }
}
然後就是layout文件:
&
http://schemas.android.com/apk/res/android">
&
&
&
&
&
&
&
&
表達式語言(Expression Language)
你可以直接在layout文件裡面使用常見的表達式:
- 數學表達式 + – / * %
- 字元串鏈接 +
- 邏輯操作符 ||
- 二元操作符 | ^
- 一元操作符 + – ! ~
- Shift &>&> &>&>&> &<&<
- 比較 == &> &< &>= &<=
- instanceof
- Grouping ()
- Literals – character, String, numeric, null
- Cast
- 函數調用
- 值域引用(Field access)
- 通過[]訪問數組裡面的對象
- 三元操作符 ?:示例:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName="@{"image_" + id}"
更多語法可以參考官網文檔:http://developer.android.com/tools/data-binding/guide.html#expression_language
更新界面
有些時候,代碼會修改我們綁定的對象的某些屬性,那麼怎麼通知界面刷新呢?下面就給出兩種方案。
方案一
讓你的綁定數據類繼承BaseObservable,然後通過調用notifyPropertyChanged方法來通知界面屬性改變,如下:
private static class User extends BaseObservable {
private String firstName;
private String lastName;
@Bindable
public String getFirstName() {
return this.firstName;
}
@Bindable
public String getLastName() {
return this.lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
在需要通知的屬性的get方法上加上@Bindable,這樣編譯階段會生成BR.[property name],然後使用這個調用方法notifyPropertyChanged就可以通知界面刷新了。如果你的數據綁定類不能繼承BaseObservable,那你就只能自己實現Observable介面,可以參考BaseObservable的實現。
方案二
Data Binding Library提供了很便利的類ObservableField,還有ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, 和 ObservableParcelable,基本上涵蓋了各種我們需要的類型。用法很簡單,如下:
private static class User {
public final ObservableField&
public final ObservableField&
public final ObservableInt age = new ObservableInt();
}
然後使用下面的代碼來訪問:
user.firstName.set("Google");
int age = user.age.get();
調用set方法時,Data Binding Library就會自動的幫我們通知界面刷新了。
綁定AdapterView
在一個實際的項目中,相信AdapterView是使用得很多的,使用官方提供給的API來進行AdapterView的綁定需要寫很多代碼,使用起來不方便,但是由於Data Binding Library提供豐富的擴展功能,所以出現了很多第三方的庫來擴展它,下面就來介紹一個比較好用的庫binding-collection-adapter,Github地址:https://github.com/evant/binding-collection-adapter
使用的時候在你的build.gradle文件裡面添加
compile "me.tatarka:bindingcollectionadapter:0.16"如果你要是用RecyclerView,還需要添加compile "me.tatarka:bindingcollectionadapter-recyclerview:0.16"下面就是ViewModel的寫法:
public class ViewModel {
public final ObservableList&
public final ItemView itemView = ItemView.of(BR.item, R.layout.item);
}
這裡用到了ObservableList, 他會在items變化的時候自動刷新界面
然後下面是layout文件:&
http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
&
&
&
&
&
&
&
& 然後是item layout: & 如果有多種樣式的布局,那麼就需要把ItemView換成ItemViewSelector, 如下:
&
&
http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
&
&
&
&
public final ItemViewSelector&
@Override
public void select(ItemView itemView, int position, String item) {
itemView.set(BR.item, position == 0 ? R.layout.item_header : R.layout.item);
}
// This is only needed if you are using a BindingListViewAdapter
@Override
public int viewTypeCount() {
return 2;
}
};
自定義綁定
正常情況下,Data Binding Library會根據屬性名去找對應的set方法,但是我們有時候需要自定義一些屬性,Data Binding Library也提供了很便利的方法讓我們來實現。
比如我們想在layout文件裡面設置ListView的emptyView,以前這個是無法做到的,只能在代碼裡面通過調用setEmptyView來做;
但是現在藉助Data Binding Library,我們可以很容易的實現這個功能了。先看layout文件:&
http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
&
&
&
&
&
&
&
&
&
app:emptyView="@{@id/empty_view}"這個代碼就用來指定emptyView,下面來看下實現的代碼:
@BindingAdapter("emptyView")
public static &
View rootView = adapterView.getRootView();
View emptyView = rootView.findViewById(viewId);
if (emptyView != null) {
adapterView.setEmptyView(emptyView);
}
}
下面我們來分析上面的代碼,@{@id/empty_view}表示引用了@id/empty_view這個id,所以它的值就是int,再看上面的setEmptyView方法,第一個參數AdapterView adapterView表示使用emptyView這個屬性的控制項,而第二個參數int viewId則是emptyView屬性傳進來的值,上面的layout可以看出來它就是R.id.empty_view,然後通過id找到控制項,然後調用原始的setEmptyView來設置。
上面的代碼來自我寫的一個Data Binding Library的示例項目DataBinding-album-sample,
Github地址:https://github.com/derron/DataBinding-album-sample
它是一個小型的項目,基本上包含了開發一個app常用到的東西,大家有興趣可以去看看。
掃描或長按關注我們的微信技術公眾號-極客聯盟
http://weixin.qq.com/r/ZklPVwHEllzprUU09xx0 (二維碼自動識別)
「崇尚自由,推崇技術,擁抱開源」 - 極客聯盟:傳播新技術理念,分享技術經驗。 打造華中區最有影響力的技術公眾號。
剛從wp轉到Android,你告訴我Android開始用mvvm了??????_??????
推薦一個很好的android 數據綁定框架 RoboBinding
寫了一個小玩具,一把Android尺子,整個項目沒有使用一處findViewById,完全使用DataBinding框架寫成。
GitHub - pengan1987/Ruler: simple ruler appAndroid的Activity生命周期十分複雜,即使是我上面的例子中,Activity也Override了5個生命周期方法。包括:
onCreate,onResume,onCreateOptionsMenu,onOptionsItemSelected,onSaveInstanceState絕大多數的App中的Activity類,都會比我的例子中複雜的多。
個人的觀點是,使用DataBinding之後,Activity和Fragment應專註於處理導航流程和視圖的生命周期,而把界面的內容完全交給ViewModel去處理。
下面重點介紹幾個DataBinding中的實用技巧
1、ObservableField的使用使用ObservableField,ObservableField會在其值更新時,自動更新界面元素,無需重新綁定,就可以更新界面的內容。使用場景如:游標隨著手指的移動而移動,並實時顯示位置數據。TouchPanelViewModel.javapublic ObservableField&
public ObservableField&
public ObservableField&
activity_main.xml
&
&
上面的代碼片段中,我們可以設定一個OnTouchListener跟蹤手指的動作,當手指觸摸屏幕時,在手指點擊的位置顯示游標,並顯示距離坐標起點的距離,手指鬆開時,隱藏距離數據,我們只需要使用
touchMode.set(true);
或者
touchMode.set(false);
就可以在代碼中同時控制顯示或隱藏xml中的兩個視圖,而不需要分別修改這兩個視圖的屬性。
同樣,我們直接使用rightCursorMargin.set(Math.round(event.getX(1)));
以及
distanceInchText.set(String.format(Locale.CANADA, "%.2f in", distanceInchFloat));
可以直接更改游標的位置或是標籤的文字,而無須獲取圖片本身。
總結:當界面控制項因UI的要求更改時,如ToggleButton更改為Checkbox,因為其背後的邏輯皆為Boolean值,只需要改動XML而ViewModel無需改動,大大提高布局的靈活性。
2、自定義Setter/BindingAdapter的使用在上面的代碼中,我們看到dynamic_marginLeft="@{touchPanelModel.leftCursorMargin}"
一行沒有命名空間,這是我們自定義的setter,其背後對應的方法如下
@BindingAdapter("dynamic_marginLeft")
public static void setMarginLeft(View view, int leftMargin) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
if (layoutParams != null) {
layoutParams.setMargins(leftMargin, layoutParams.bottomMargin, layoutParams.rightMargin, layoutParams.bottomMargin);
view.setLayoutParams(layoutParams);
}
}
雖然Android官方的android:layout_marginLeft屬性不能直接被綁定,但是通過自定義Setter,我們仍然可以實現控制項位置與ViewModel屬性的綁定,配合上面介紹的ObservableField,從而簡易的實現了控制項隨手指移動的功能。
總結:自定義setter可以大大提高XML的功能,不僅可以用來綁定viewModel里的值,也可以綁定資源,非常靈活,如myOwnTextSetter="@{@string/some_text_resource}"
在使用的時候,要注意setter的命名是全局的,既不要在兩個viewModel文件中出現同樣annotation的BindingAdapter。
3、app命名空間和事件監聽Google官方在其文檔中介紹了綁定Event的方法,但是介紹的非常簡單,其實使用XML中的app命名空間,控制項類的所有公有方法都是可以在XML中訪問的,如下面這段代碼&
上面的app:onTouchListener,實際上對應的是View.setOnTouchListener,所以後面所跟的參數,就應當是View.OnTouchListener介面的實現。
public class TouchPanelViewModel {
....
public OnPanelTouchListener touchListener;
....
touchListener = new OnPanelTouchListener();
....
public class OnPanelTouchListener implements View.OnTouchListener {....}
大概的代碼結構就是這樣的,OnPanelTouchListener內部類實現View.OnTouchListener介面,在界面事件發生時就會被呼叫到。這也是實現雙向綁定的基礎。
總結:app命名空間基本上把所有視圖的公有setter開放給XML使用,通過XML設置事件監聽,可以大大簡化Java類中設置監聽的代碼,利用ViewModel本身作為事件的handler,可以實現XML布局與ViewModel的雙向通信,是實現雙向綁定的基礎。
4、雙向綁定的實現利用ObservableField和EventHandler,我們有了XML布局和ViewModel之間免維護的數據通道,進而實現雙向的數據綁定,向下面一貼的作者致敬https://medium.com/@fabioCollini/android-data-binding-f9f9d3afc761#.d975gr53hXML&
ViewModel
public class Echo {
public ObservableField&
public TextWatcher watcher = new TextWatcherAdapter() {
@Override
public void afterTextChanged(Editable s) {
if (!Objects.equals(text.get(), s.toString())) {
text.set(s.toString());
}
}
};
}
當使用雙向綁定之後,程序的其他部分可以直接訪問Echo類的text屬性獲取或修改編輯框的字元串,而完全無需關心界面布局的實現。
總結:雙向綁定將維護界面狀態的成本降到最低,我們永遠只需要關心ViewModel實例的狀態,而無需關心界面本身的實現及在屏幕上的狀態,對於RecyclerView中的Item這樣頻繁重繪的部分,維護ViewHolder的狀態往往十分繁瑣,是非常適合於使用ViewModel的場合。一直在內部推廣MVVM,從wp7,wp8,Metro app到wpf,再到iOS的RAC,這次Google官方發布了MVVM框架中最重要的binding部分,雖然還不完善,但是我內心表示已經很酸爽了,目前android UI的xml非常簡單,所以大量的代碼堆疊到了activity和fragment上,導致大部分一開始就做Android的程序員沒有架構思想,只是在調用API,這次google的動作路線作用更大一些,但是要做到完美還需要很長的路要走。
回答問題:對於簡單view,拆解單個MV實際意義不大,一般的做法是把MVVM再看成UI層,下層部署類SOA服務,對於複雜的view,視情況而定,可以建立新的MVVM子集閑聊中打字,有時間再整理下,待續分享一個demo sys1yagi/data-binding-sample · GitHub
ruzhan123/awaker
這是我最近使用mvvm玩的一個業餘項目,之前也是玩mvp的。
玩了好幾個界面,普通的,列表的,mvvm的確是加強版mvp
MVVM目前還不完美,已撤回MVP。MVVM最大的問題是 VM中混合了一些V的操作。導致我用起來感覺很不舒服。例如驗證用戶輸入,VM可以直接改變界面,而不用經過V。例如兩個view有依賴關係,在VM中無法直接實現。如果VM持有V的對象,那和MVP有什麼區別。一些View的初始化工作無法在VM中實現,在V中實現又和MVVM的理念衝突。總之就是用起來心裡好難受!
現在databanding有項目在使用了嗎?會不會有什麼兼容性或者穩定性之類的問題
剛準備轉android,感覺,google要是想干,就原封不動的把WPF的那一套,抄襲過來就完美了。
緊跟前端的發展路線,好樣的
推薦閱讀:
※一份理想的移動應用市場的分析報告,應該包含哪些內容?
※國內 Android 應用生態中的有哪些黑產?
※OpenGL ES 對 DirectX?
※雙核1.7GHz 四核1.2GHz 哪個更強?
※Android 和 Chrome OS 會最終合併成一個平台嗎?如何合併?