Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發模式之MVC,MVP和MVVM的簡單介紹與區別

Android開發模式之MVC,MVP和MVVM的簡單介紹與區別

編輯:關於Android編程

相信大家對MVC,MVP和MVVM都不陌生,作為三個最耳熟能詳的Android框架,它們的應用可以是非常廣泛的,但是對於一些新手來說,可能對於區分它們三個都有困難,更別說在實際的項目中應用了,有些時候想用MVP的,代碼寫著寫著就變成了MVC,久而久之就對它們三個的選擇產生了恐懼感,如果你也是這樣的人群,那麼這篇文章可能會對你有很大的幫助,希望大家看完都會有收獲吧!

文章重點:

(1)了解並區分MVC,MVP,MVVM。

(2)知道這三種模式在Android中如何使用。

(3)走出data binding的誤區。

(4)了解MVP+data binding的開發模式。

本篇文章的demo我將會上傳到我的github上。

水之積也不厚,則其負大舟也無力

正如莊子在逍遙游中說的,如果水不夠深,那就沒有能夠擔負大船的力量 。所以在真正開始涉及具體的代碼之前,我們要先對MVC,MVP和MVVM做一個初步的了解。如果各位同學對此已經有所了解了,可以選擇性跳過這一節。

MVC

MVC,Model View Controller,是軟件架構中最常見的一種框架,簡單來說就是通過controller的控制去操作model層的數據,並且返回給view層展示,具體見下圖

mvc

當用戶出發事件的時候,view層會發送指令到controller層,接著controller去通知model層更新數據,model層更新完數據以後直接顯示在view層上,這就是MVC的工作原理。

那具體到Android上是怎麼樣一個情況呢?

大家都知道一個Android工程有什麼對吧,有java的class文件,有res文件夾,裡面是各種資源,還有類似manifest文件等等。對於原生的Android項目來說,layout.xml裡面的xml文件就對應於MVC的view層,裡面都是一些view的布局代碼,而各種java bean,還有一些類似repository類就對應於model層,至於controller層嘛,當然就是各種activity咯。大家可以試著套用我上面說的MVC的工作原理是理解。比如你的界面有一個按鈕,按下這個按鈕去網絡上下載一個文件,這個按鈕是view層的,是使用xml來寫的,而那些和網絡連接相關的代碼寫在其他類裡,比如你可以寫一個專門的networkHelper類,這個就是model層,那怎麼連接這兩層呢?是通過button.setOnClickListener()這個函數,這個函數就寫在了activity中,對應於controller層。是不是很清晰。

大家想過這樣會有什麼問題嗎?顯然是有的,不然為什麼會有MVP和MVVM的誕生呢,是吧。問題就在於xml作為view層,控制能力實在太弱了,你想去動態的改變一個頁面的背景,或者動態的隱藏/顯示一個按鈕,這些都沒辦法在xml中做,只能把代碼寫在activity中,造成了activity既是controller層,又是view層的這樣一個窘境。大家回想一下自己寫的代碼,如果是一個邏輯很復雜的頁面,activity或者fragment是不是動辄上千行呢?這樣不僅寫起來麻煩,維護起來更是噩夢。(當然看過Android源碼的同學其實會發現上千行的代碼不算啥,一個RecyclerView.class的代碼都快上萬行了呢。。)

MVC還有一個重要的缺陷,大家看上面那幅圖,view層和model層是相互可知的,這意味著兩層之間存在耦合,耦合對於一個大型程序來說是非常致命的,因為這表示開發,測試,維護都需要花大量的精力。

正因為MVC有這樣那樣的缺點,所以才演化出了MVP和MVVM這兩種框架。

MVP

MVP作為MVC的演化,解決了MVC不少的缺點,對於Android來說,MVP的model層相對於MVC是一樣的,而activity和fragment不再是controller層,而是純粹的view層,所有關於用戶事件的轉發全部交由presenter層處理。下面還是讓我們看圖

mvp

從圖中就可以看出,最明顯的差別就是view層和model層不再相互可知,完全的解耦,取而代之的presenter層充當了橋梁的作用,用於操作view層發出的事件傳遞到presenter層中,presenter層去操作model層,並且將數據返回給view層,整個過程中view層和model層完全沒有聯系。看到這裡大家可能會問,雖然view層和model層解耦了,但是view層和presenter層不是耦合在一起了嗎?其實不是的,對於view層和presenter層的通信,我們是可以通過接口實現的,具體的意思就是說我們的activity,fragment可以去實現實現定義好的接口,而在對應的presenter中通過接口調用方法。不僅如此,我們還可以編寫測試用的View,模擬用戶的各種操作,從而實現對Presenter的測試。這就解決了MVC模式中測試,維護難的問題。

當然,其實最好的方式是使用fragment作為view層,而activity則是用於創建view層(fragment)和presenter層(presenter)的一個控制器。

MVVM

MVVM最早是由微軟提出的

mvvm

這裡要感謝泡在網上的日子,因為前面看到的三張圖我都是從它的博客中摘取的,如果有人知道不允許這樣做的話請告訴我,我會從我的博客中刪除的,謝謝。

從圖中看出,它和MVP的區別貌似不大,只不過是presenter層換成了viewmodel層,還有一點就是view層和viewmodel層是相互綁定的關系,這意味著當你更新viewmodel層的數據的時候,view層會相應的變動ui。

我們很難去說MVP和MVVM這兩個MVC的變種孰優孰劣,還是要具體情況具體分析。

紙上得來終覺淺,絕知此事要躬行

對於程序員來說,空談是最沒效率的一種方式,相信大家看了我上面對於三種模式的分析,或多或少都會有點雲裡霧裡,下面讓我們結合代碼來看看。

讓我們試想一下下面這個情景,用戶點擊一個按鈕A,獲取github上對應公司對應倉庫中貢獻排行第一的任的名字,然後我們還會有一個按鈕B,用戶點擊按鈕B,界面上排行第一的那個人的名字就會換成自己的。

MVC

MVC實現是最簡單的。

首先看對應view層的xml文件

  http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/container"android:orientation="vertical"tools:context=".ui.view.MainActivity"android:fitsSystemWindows="true">android:text="get"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="get"/>android:text="change"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="change"/>android:id="@+id/top_contributor"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="30sp"/>

很簡單,兩個Button一個TextView

接著看對應controller層的activity

  publicclassMainActivityextendsAppCompatActivity{privateProcessDialogdialog;privateContributorcontributor=newContributor();privateTextViewtopContributor;privateSubscribercontributorSub=newSubscriber(){@OverridepublicvoidonStart(){showProgress();}@OverridepublicvoidonCompleted(){}@OverridepublicvoidonError(Throwablee){}@OverridepublicvoidonNext(Contributorcontributor){MainActivity.this.contributor=contributor;topContributor.setText(contributor.login);dismissProgress();}};@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);topContributor=(TextView)findViewById(R.id.top_contributor);}publicvoidget(Viewview){getTopContributor("square","retrofit");}publicvoidchange(Viewview){contributor.login="zjutkz";topContributor.setText(contributor.login);}publicvoidgetTopContributor(Stringowner,Stringrepo){GitHubApi.getContributors(owner,repo).take(1).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread()).map(newFunc1,Contributor>(){@OverridepublicContributorcall(Listcontributors){returncontributors.get(0);}}).subscribe(contributorSub);}publicvoidshowProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.showMessage("正在加載...");}publicvoiddismissProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.dismiss();}}

我們看一下get()方法中調用的getTopContributor方法

  publicvoidgetTopContributor(Stringowner,Stringrepo){GitHubApi.getContributors(owner,repo).take(1).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread()).map(newFunc1,Contributor>(){@OverridepublicContributorcall(Listcontributors){returncontributors.get(0);}}).subscribe(contributorSub);}

熟悉rxjava和retrofit的同學應該都明白這是啥意思,如果對這兩個開源庫不熟悉也沒事,可以參考給 Android 開發者的 RxJava 詳解和用 Retrofit 2 簡化 HTTP 請求這兩篇文章。

對於這裡大家只要知道這段代碼的意思就是去獲取github上owner公司中的repo倉庫裡貢獻排名第一的那個人。貢獻者是通過Contributor這個java bean存儲的。

  publicclassContributor{publicStringlogin;publicintcontributions;@OverridepublicStringtoString(){returnlogin+","+contributions;}}

很簡單,login表示貢獻者的名字,contributor表示貢獻的次數。

然後通過rxjava的subscriber中的onNext()函數得到這個數據。

  privateSubscribercontributorSub=newSubscriber(){@OverridepublicvoidonStart(){showProgress();}@OverridepublicvoidonCompleted(){}@OverridepublicvoidonError(Throwablee){}@OverridepublicvoidonNext(Contributorcontributor){MainActivity.this.contributor=contributor;topContributor.setText(contributor.login);dismissProgress();}};

至於另外那個change按鈕的工作大家應該都看得懂,這裡不重復了。

好了,我們來回顧一遍整個流程。

首先在xml中寫好布局代碼。

其次,activity作為一個controller,裡面的邏輯是監聽用戶點擊按鈕並作出相應的操作。比如針對get按鈕,做的工作就是調用GithubApi的方法去獲取數據。

GithubApi,Contributor等類則表示MVC中的model層,裡面是數據和一些具體的邏輯操作。

說完了流程再來看看問題,還記得我們前面說的嗎,MVC在Android上的應用,一個具體的問題就是activity的責任過重,既是controller又是view。這裡是怎麼體現的呢?看了代碼大家發現其中有一個progressDialog,在加載數據的時候顯示,加載完了以後取消,邏輯其實是view層的邏輯,但是這個我們沒辦法寫到xml裡面啊,包括TextView.setTextView(),這個也一樣。我們只能把這些邏輯寫到activity中,這就造成了activity的臃腫,這個例子可能還好,如果是一個復雜的頁面呢?大家自己想象一下。

MVP

通過具體的代碼大家知道了MVC在Android上是如何工作的,也知道了它的缺點,那MVP是如何修正的呢?

這裡先向大家推薦github上的一個第三方庫,通過這個庫大家可以很輕松的實現MVP。好了,還是看代碼吧。

首先還是xml

  http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/container"android:orientation="vertical"tools:context=".ui.view.MainActivity"android:fitsSystemWindows="true">android:text="get"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="get"/>android:text="change"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="change"/>android:id="@+id/top_contributor"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="30sp"/>

這個和MVC是一樣的,畢竟界面的形式是一樣的嘛。

接下去,我們看一個接口。

  publicinterfaceContributorViewextendsMvpView{voidonLoadContributorStart();voidonLoadContributorComplete(ContributortopContributor);voidonChangeContributorName(Stringname);}

這個接口起什麼作用呢?還記得我之前說的嗎?MVP模式中,view層和presenter層靠的就是接口進行連接,而具體的就是上面的這個了,裡面定義的三個方法,第一個是開始獲取數據,第二個是獲取數據成功,第三個是改名。我們的view層(activity)只要實現這個接口就可以了。

下面看activity的代碼

  publicclassMainActivityextendsMvpActivityimplementsContributorView{privateProcessDialogdialog;privateTextViewtopContributor;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);topContributor=(TextView)findViewById(R.id.top_contributor);}@NonNull@OverridepublicContributorPresentercreatePresenter(){returnnewContributorPresenter();}publicvoidget(Viewview){getPresenter().get("square","retrofit");}publicvoidchange(Viewview){getPresenter().change();}@OverridepublicvoidonLoadContributorStart(){showProgress();}@OverridepublicvoidonLoadContributorComplete(Contributorcontributor){topContributor.setText(contributor.toString());dismissProgress();}@OverridepublicvoidonChangeContributorName(Stringname){topContributor.setText(name);}publicvoidshowProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.showMessage("正在加載...");}publicvoiddismissProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.dismiss();}}

它繼承自MvpActivity,實現了剛才的ContributorView接口。繼承的那個MvpActivity大家這裡不用太關心主要是做了一些初始化和生命周期的封裝。我們只要關心這個activity作為view層,到底是怎麼工作的。

  publicvoidget(Viewview){getPresenter().get("square","retrofit");}publicvoidchange(Viewview){getPresenter().change();}

get()和change()這兩個方法是我們點擊按鈕以後執行的,可以看到,裡面完完全全沒有任何和model層邏輯相關的東西,只是簡單的委托給了presenter,那我們再看看presenter層做了什麼

  publicclassContributorPresenterextendsMvpBasePresenter{privateSubscribercontributorSub=newSubscriber(){@OverridepublicvoidonStart(){ContributorViewview=getView();if(view!=null){view.onLoadContributorStart();}}@OverridepublicvoidonCompleted(){}@OverridepublicvoidonError(Throwablee){}@OverridepublicvoidonNext(ContributortopContributor){ContributorViewview=getView();if(view!=null){view.onLoadContributorComplete(topContributor);}}};publicvoidget(Stringowner,Stringrepo){GitHubApi.getContributors(owner,repo).take(1).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread()).map(newFunc1,Contributor>(){@OverridepublicContributorcall(Listcontributors){returncontributors.get(0);}}).subscribe(contributorSub);}publicvoidchange(){ContributorViewview=getView();if(view!=null){view.onChangeContributorName("zjutkz");}}}

其實就是把剛才MVC中activity的那部分和model層相關的邏輯抽取了出來,並且在相應的時機調用ContributorView接口對應的方法,而我們的activity是實現了這個接口的,自然會走到對應的方法中。

好了,我們來捋一捋。

首先,和MVC最大的不同,MVP把activity作為了view層,通過代碼也可以看到,整個activity沒有任何和model層相關的邏輯代碼,取而代之的是把代碼放到了presenter層中,presenter獲取了model層的數據之後,通過接口的形式將view層需要的數據返回給它就OK了。

這樣的好處是什麼呢?首先,activity的代碼邏輯減少了,其次,view層和model層完全解耦,具體來說,如果你需要測試一個http請求是否順利,你不需要寫一個activity,只需要寫一個java類,實現對應的接口,presenter獲取了數據自然會調用相應的方法,相應的,你也可以自己在presenter中mock數據,分發給view層,用來測試布局是否正確。

MVVM

首先在看這段內容之前,你需要保證你對data binding框架有基礎的了解。不了解的同學可以去看下這篇文章。在接下去讓我們開始探索MVVM,MVVM最近在Android上可謂十分之火,最主要的原因就是谷歌推出了data binding這個框架,可以輕松的實現MVVM。但是,我在網上查閱關於Android的data binding資料的時候,發現國內有很多人都誤解了,首先,我們從一篇錯誤的文章開始。當然我在這裡引用這篇文章也是對事不對人,如果對文章的作者產生了不好的影響我這裡說一聲抱歉。

上面那篇文章是一個關於data binding的使用,看起來很美好,但是,其中有一個錯誤可以說是非常,非常,非常嚴重的。

blob.png

它竟然說data binding的viewmodel層是binding類,其實不止是這篇文章,其他有一些開發者寫的關於data binding的文章裡都犯了一樣的錯誤。大家如果也有這樣的概念,請務必糾正過來!!

說完了錯誤的概念,那data binding中真正的viewmodel是什麼呢?我們還是以之前MVC,MVP的那個例子做引導。

首先是view層,這沒啥好說的,和MVP一樣,view層就是xml和activity。

  http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/container"android:orientation="vertical"tools:context=".ui.view.MainActivity"android:fitsSystemWindows="true">android:text="get"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="get"/>android:text="change"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="change"/>android:id="@+id/top_contributor"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="30sp"/>

  publicclassMainActivityextendsAppCompatActivity{privateSubscribercontributorSub=newSubscriber(){@OverridepublicvoidonStart(){showProgress();}@OverridepublicvoidonCompleted(){}@OverridepublicvoidonError(Throwablee){}@OverridepublicvoidonNext(Contributorcontributor){binding.setContributor(contributor);dismissProgress();}};privateProcessDialogdialog;privateMvvmActivityMainBindingbinding;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);binding=DataBindingUtil.setContentView(this,R.layout.mvvm_activity_main);}publicvoidget(Viewview){getContributors("square","retrofit");}publicvoidchange(Viewview){if(binding.getContributor()!=null){binding.getContributor().setLogin("zjutkz");}}publicvoidshowProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.showMessage("正在加載...");}publicvoiddismissProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.dismiss();}publicvoidgetContributors(Stringowner,Stringrepo){GitHubApi.getContributors(owner,repo).take(1).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread()).map(newFunc1,Contributor>(){@OverridepublicContributorcall(Listcontributors){returncontributors.get(0);}}).subscribe(contributorSub);}}

如果你對data binding框架是有了解的,上面的代碼你能輕松的看懂。

那model層又是什麼呢?當然就是那些和數據相關的類,GithubApi等等。

重點來了,viewmodel層呢?好吧,viewmodel層就是是Contributor類!大家不要驚訝,我慢慢的來說。

  publicclassContributorextendsBaseObservable{privateStringlogin;privateintcontributions;@BindablepublicStringgetLogin(){returnlogin;}@BindablepublicintgetContributions(){returncontributions;}publicvoidsetLogin(Stringlogin){this.login=login;notifyPropertyChanged(BR.login);}publicvoidsetContributions(intcontributions){this.contributions=contributions;notifyPropertyChanged(BR.contributions);}@OverridepublicStringtoString(){returnlogin+","+contributions;}}

我們可以看到,Contributor和MVP相比,繼承自了BaseObservable,有基礎的同學都知道這是為了當Contributor內部的variable改變的時候ui可以同步的作出響應。

我為什麼說Contributor是一個viewmodel呢。大家還記得viewmodel的概念嗎?view和viewmodel相互綁定在一起,viewmodel的改變會同步到view層,從而view層作出響應。這不就是Contributor和xml中那些組件元素的關系嗎?所以,大家不要被binding類迷惑了,data binding框架中的viewmodel是自己定義的那些看似是model類的東西!比如這裡的Contributor!

話說到這裡,那binding類又是什麼呢?其實具體對應到之前MVVM的那張圖就很好理解了,我們想一下,binding類的工作是什麼?

  binding=DataBindingUtil.setContentView(this,R.layout.mvvm_activity_main);binding.setContributor(contributor);

首先,binding要通過DataBindingUtil.setContentView()方法將xml,也就是view層設定。

接著,通過setXXX()方法將viewmodel層注入進去。

由於這兩個工作,view層(xml的各個組件)和viewmodel層(contributor)綁定在了一起。

好了,大家知道了嗎,binding類,其實就是上圖中view和viewmodel中間的那根線啊!!

真理在荒謬被證實以前,都只是暗室裡的裝飾

前面討論了MVC,MVP和MVVM具體的實現方案,大家肯定都了解了它們三者的關系和使用方式。但是,這裡我想說,不要把一個框架看作萬能的,其實MVP和MVVM都是有自己的缺陷的!下面我一一來說。

MVP

MVP的問題在於,由於我們使用了接口的方式去連接view層和presenter層,這樣就導致了一個問題,如果你有一個邏輯很復雜的頁面,你的接口會有很多,十幾二十個都不足為奇。想象一個app中有很多個這樣復雜的頁面,維護接口的成本就會非常的大。

這個問題的解決方案就是你得根據自己的業務邏輯去斟酌著寫接口。你可以定義一些基類接口,把一些公共的邏輯,比如網絡請求成功失敗,toast等等放在裡面,之後你再定義新的接口的時候可以繼承自那些基類,這樣會好不少。

MVVM

MVVM的問題呢,其實和MVC有一點像。data binding框架解決了數據綁定的問題,但是view層還是會過重,大家可以看我上面那個MVVM模式下的activity

  publicclassMainActivityextendsAppCompatActivity{privateSubscribercontributorSub=newSubscriber(){@OverridepublicvoidonStart(){showProgress();}@OverridepublicvoidonCompleted(){}@OverridepublicvoidonError(Throwablee){}@OverridepublicvoidonNext(Contributorcontributor){binding.setContributor(contributor);dismissProgress();}};privateProcessDialogdialog;privateMvvmActivityMainBindingbinding;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);binding=DataBindingUtil.setContentView(this,R.layout.mvvm_activity_main);}publicvoidget(Viewview){getContributors("square","retrofit");}publicvoidchange(Viewview){if(binding.getContributor()!=null){binding.getContributor().setLogin("zjutkz");}}publicvoidshowProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.showMessage("正在加載...");}publicvoiddismissProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.dismiss();}publicvoidgetContributors(Stringowner,Stringrepo){GitHubApi.getContributors(owner,repo).take(1).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread()).map(newFunc1,Contributor>(){@OverridepublicContributorcall(Listcontributors){returncontributors.get(0);}}).subscribe(contributorSub);}}

大家有沒有發現,activity在MVVM中應該是view層的,但是裡面卻和MVC一樣寫了對model的處理。有人會說你可以把對model的處理放到viewmodel層中,這樣不是更符合MVVM的設計理念嗎?這樣確實可以,但是progressDialog的show和dismiss呢?你怎麼在viewmodel層中控制?這是view層的東西啊,而且在xml中也沒有,我相信會有解決的方案,但是我們有沒有一種更加便捷的方式呢?

路漫漫其修遠兮,吾將上下而求索

其實,真正的最佳實踐都是人想出來的,我們為何不結合一下MVP和MVVM的特點呢?其實谷歌已經做了這樣的事,大家可以看下這個。沒錯,就是MVP+data binding,我們可以使用presenter去做和model層的通信,並且使用data binding去輕松的bind data。還是讓我們看代碼吧。

首先還是view層。

  http://schemas.android.com/apk/res/android">android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/container"android:orientation="vertical"android:fitsSystemWindows="true">android:id="@+id/get"android:text="get"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="get"/>android:id="@+id/change"android:text="change"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="change"/>android:id="@+id/top_contributor"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="30sp"android:text="@{contributor.login}"/>

  publicclassMainActivityextendsMvpActivityimplementsContributorView{privateProcessDialogdialog;privateActivityMainBindingbinding;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);binding=DataBindingUtil.setContentView(this,R.layout.activity_main);}@NonNull@OverridepublicContributorPresentercreatePresenter(){returnnewContributorPresenter();}publicvoidget(Viewview){getPresenter().get("square","retrofit");}publicvoidchange(Viewview){if(binding.getContributor()!=null){binding.getContributor().setLogin("zjutkz");}}@OverridepublicvoidonLoadContributorStart(){showProgress();}@OverridepublicvoidonLoadContributorComplete(Contributorcontributor){binding.setContributor(contributor);dismissProgress();}publicvoidshowProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.showMessage("正在加載...");}publicvoiddismissProgress(){if(dialog==null){dialog=newProcessDialog(this);}dialog.dismiss();}}

然後是presenter層

  publicclassContributorPresenterextendsMvpBasePresenter{privateSubscribercontributorSub=newSubscriber(){@OverridepublicvoidonStart(){ContributorViewview=getView();if(view!=null){view.onLoadContributorStart();}}@OverridepublicvoidonCompleted(){}@OverridepublicvoidonError(Throwablee){}@OverridepublicvoidonNext(ContributortopContributor){ContributorViewview=getView();if(view!=null){view.onLoadContributorComplete(topContributor);}}};publicvoidget(Stringowner,Stringrepo){GitHubApi.getContributors(owner,repo).take(1).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread()).map(newFunc1,Contributor>(){@OverridepublicContributorcall(Listcontributors){returncontributors.get(0);}}).subscribe(contributorSub);}}

model層就是GithubApi等等。

我們使用了data binding框架去節省了類似findViewById和數據綁定的時間,又使用了presenter去將業務邏輯和view層分離。

當然這也不是固定的,你大可以在viewmodel中實現相應的接口,presenter層的數據直接發送到viewmodel中,在viewmodel裡更新,因為view和viewmodel是綁定的,這樣view也會相應的作出反應。

說到這裡,我還是想重復剛才的那句話,最佳實踐都是人想出來的,用這些框架根本的原因也是為了盡量低的耦合性和盡量高的可復用性。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved