选择恐惧症的福音!教你认清MVC,MVP和MVVM

相信你们对MVC,MVP和MVVM都不陌生,做为三个最耳熟能详的Android框架,它们的应用能够是很是普遍的,可是对于一些新手来讲,可能对于区分它们三个都有困难,更别说在实际的项目中应用了,有些时候想用MVP的,代码写着写着就变成了MVC,长此以往就对它们三个的选择产生了恐惧感,若是你也是这样的人群,那么这篇文章可能会对你有很大的帮助,但愿你们看完都会有收获吧!java

文章重点:android

(1)了解并区分MVC,MVP,MVVM。git

(2)知道这三种模式在Android中如何使用。程序员

(3)走出data binding的误区。github

(4)了解MVP+data binding的开发模式。网络

水之积也不厚,则其负大舟也无力

正如庄子在逍遥游中说的,若是水不够深,那就没有可以担负大船的力量 。因此在真正开始涉及具体的代码以前,咱们要先对MVC,MVP和MVVM作一个初步的了解。若是各位同窗对此已经有所了解了,能够选择性跳过这一节。架构

MVCapp

MVC,Model View Controller,是软件架构中最多见的一种框架,简单来讲就是经过controller的控制去操做model层的数据,而且返回给view层展现,具体见下图框架

 

 

当用户出发事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据之后直接显示在view层上,这就是MVC的工做原理。mvvm

那具体到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层处理。下面仍是让咱们看图

 

 

从图中就能够看出,最明显的差异就是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最先是由微软提出的

 

 

这里要感谢泡在网上的日子,由于前面看到的三张图我都是从它的博客中摘取的,若是有人知道不容许这样作的话请告诉我,我会从个人博客中删除的,谢谢。

从图中看出,它和MVP的区别貌似不大,只不过是presenter层换成了viewmodel层,还有一点就是view层和viewmodel层是相互绑定的关系,这意味着当你更新viewmodel层的数据的时候,view层会相应的变更ui。

咱们很难去说MVP和MVVM这两个MVC的变种孰优孰劣,仍是要具体状况具体分析。

纸上得来终觉浅,绝知此事要躬行

对于程序员来讲,空谈是最没效率的一种方式,相信你们看了我上面对于三种模式的分析,或多或少都会有点云里雾里,下面让咱们结合代码来看看。

让咱们试想一下下面这个情景,用户点击一个按钮A,获取github上对应公司对应仓库中贡献排行第一的任的名字,而后咱们还会有一个按钮B,用户点击按钮B,界面上排行第一的那我的的名字就会换成本身的。

MVC

若是想学习Java工程化、高性能及分布式、深刻浅出。微服务、Spring,MyBatis,Netty源码分析的朋友能够加个人Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给你们。

MVC实现是最简单的。

首先看对应view层的xml文件

 
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="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"> <Button android:text="get" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="get"/> <Button android:text="change" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="change"/> <TextView android:id="@+id/top_contributor" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="30sp"/> </LinearLayout>

很简单,两个Button一个TextView

接着看对应controller层的activity

 
public class MainActivity extends AppCompatActivity { private ProcessDialog dialog; private Contributor contributor = new Contributor(); private TextView topContributor; private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() { @Override public void onStart() { showProgress(); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Contributor contributor) { MainActivity.this.contributor = contributor; topContributor.setText(contributor.login); dismissProgress(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); topContributor = (TextView)findViewById(R.id.top_contributor); } public void get(View view){ getTopContributor("square", "retrofit"); } public void change(View view){ contributor.login = "zjutkz"; topContributor.setText(contributor.login); } public void getTopContributor(String owner,String repo){ GitHubApi.getContributors(owner, repo) .take(1) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.newThread()) .map(new Func1<List<Contributor>, Contributor>() { @Override public Contributor call(List<Contributor> contributors) { return contributors.get(0); } }) .subscribe(contributorSub); } public void showProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.showMessage("正在加载..."); } public void dismissProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.dismiss(); } }

咱们看一下get()方法中调用的getTopContributor方法

 
public void getTopContributor(String owner,String repo){ GitHubApi.getContributors(owner, repo) .take(1) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.newThread()) .map(new Func1<List<Contributor>, Contributor>() { @Override public Contributor call(List<Contributor> contributors) { return contributors.get(0); } }) .subscribe(contributorSub); }

熟悉rxjava和retrofit的同窗应该都明白这是啥意思,若是对这两个开源库不熟悉也没事

对于这里你们只要知道这段代码的意思就是去获取github上owner公司中的repo仓库里贡献排名第一的那我的。贡献者是经过Contributor这个java bean存储的。

 
public class Contributor { public String login; public int contributions; @Override public String toString() { return login + ", " + contributions; } }

很简单,login表示贡献者的名字,contributor表示贡献的次数。

而后经过rxjava的subscriber中的onNext()函数获得这个数据。

 
private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() { @Override public void onStart() { showProgress(); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Contributor contributor) { 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

 
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="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"> <Button android:text="get" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="get"/> <Button android:text="change" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="change"/> <TextView android:id="@+id/top_contributor" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="30sp"/> </LinearLayout>

这个和MVC是同样的,毕竟界面的形式是同样的嘛。

接下去,咱们看一个接口。

 
public interface ContributorView extends MvpView { void onLoadContributorStart(); void onLoadContributorComplete(Contributor topContributor); void onChangeContributorName(String name); }

这个接口起什么做用呢?还记得我以前说的吗?MVP模式中,view层和presenter层靠的就是接口进行链接,而具体的就是上面的这个了,里面定义的三个方法,第一个是开始获取数据,第二个是获取数据成功,第三个是更名。咱们的view层(activity)只要实现这个接口就能够了。

下面看activity的代码

 
public class MainActivity extends MvpActivity<ContributorView,ContributorPresenter> implements ContributorView { private ProcessDialog dialog; private TextView topContributor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); topContributor = (TextView)findViewById(R.id.top_contributor); } @NonNull @Override public ContributorPresenter createPresenter() { return new ContributorPresenter(); } public void get(View view){ getPresenter().get("square", "retrofit"); } public void change(View view){ getPresenter().change(); } @Override public void onLoadContributorStart() { showProgress(); } @Override public void onLoadContributorComplete(Contributor contributor) { topContributor.setText(contributor.toString()); dismissProgress(); } @Override public void onChangeContributorName(String name) { topContributor.setText(name); } public void showProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.showMessage("正在加载..."); } public void dismissProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.dismiss(); } }

它继承自MvpActivity,实现了刚才的ContributorView接口。继承的那个MvpActivity你们这里不用太关心主要是作了一些初始化和生命周期的封装。咱们只要关心这个activity做为view层,究竟是怎么工做的。

 
public void get(View view){ getPresenter().get("square", "retrofit"); } public void change(View view){ getPresenter().change(); }

get()和change()这两个方法是咱们点击按钮之后执行的,能够看到,里面完彻底全没有任何和model层逻辑相关的东西,只是简单的委托给了presenter,那咱们再看看presenter层作了什么

若是想学习Java工程化、高性能及分布式、深刻浅出。微服务、Spring,MyBatis,Netty源码分析的朋友能够加个人Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给你们。

 
public class ContributorPresenter extends MvpBasePresenter<ContributorView> { private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() { @Override public void onStart() { ContributorView view = getView(); if(view != null){ view.onLoadContributorStart(); } } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Contributor topContributor) { ContributorView view = getView(); if(view != null){ view.onLoadContributorComplete(topContributor); } } }; public void get(String owner,String repo){ GitHubApi.getContributors(owner, repo) .take(1) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.newThread()) .map(new Func1<List<Contributor>, Contributor>() { @Override public Contributor call(List<Contributor> contributors) { return contributors.get(0); } }) .subscribe(contributorSub); } public void change(){ ContributorView view = 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的使用,看起来很美好,可是,其中有一个错误能够说是很是,很是,很是严重的。

 

 

它居然说data binding的viewmodel层是binding类,其实不止是这篇文章,其余有一些开发者写的关于data binding的文章里都犯了同样的错误。你们若是也有这样的概念,请务必纠正过来!!

说完了错误的概念,那data binding中真正的viewmodel是什么呢?咱们仍是以以前MVC,MVP的那个例子作引导。

首先是view层,这没啥好说的,和MVP同样,只不过多了数据绑定。view层就是xml和activity。

 
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="contributor" type="zjutkz.com.mvvm.viewmodel.Contributor"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/container" android:orientation="vertical" android:fitsSystemWindows="true"> <Button android:id="@+id/get" android:text="get" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="get"/> <Button android:id="@+id/change" android:text="change" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="change"/> <TextView 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}"/> </LinearLayout> </layout> public class MainActivity extends AppCompatActivity { private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() { @Override public void onStart() { showProgress(); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Contributor contributor) { binding.setContributor(contributor); dismissProgress(); } }; private ProcessDialog dialog; private MvvmActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.mvvm_activity_main); } public void get(View view){ getContributors("square", "retrofit"); } public void change(View view){ if(binding.getContributor() != null){ binding.getContributor().setLogin("zjutkz"); } } public void showProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.showMessage("正在加载..."); } public void dismissProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.dismiss(); } public void getContributors(String owner,String repo){ GitHubApi.getContributors(owner, repo) .take(1) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.newThread()) .map(new Func1<List<Contributor>, Contributor>() { @Override public Contributor call(List<Contributor> contributors) { return contributors.get(0); } }) .subscribe(contributorSub); } }

若是你对data binding框架是有了解的,上面的代码你能轻松的看懂。

那model层又是什么呢?固然就是那些和数据相关的类,GithubApi等等。

重点来了,viewmodel层呢?好吧,viewmodel层就是是Contributor类!你们不要惊讶,我慢慢的来讲。

 
public class Contributor extends BaseObservable{ private String login; private int contributions; @Bindable public String getLogin(){ return login; } @Bindable public int getContributions(){ return contributions; } public void setLogin(String login){ this.login = login; notifyPropertyChanged(BR.login); } public void setContributions(int contributions){ this.contributions = contributions; notifyPropertyChanged(BR.contributions); } @Override public String toString() { return login + ", " + 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);

若是想学习Java工程化、高性能及分布式、深刻浅出。微服务、Spring,MyBatis,Netty源码分析的朋友能够加个人Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给你们。

首先,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

 
public class MainActivity extends AppCompatActivity { private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() { @Override public void onStart() { showProgress(); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Contributor contributor) { binding.setContributor(contributor); dismissProgress(); } }; private ProcessDialog dialog; private MvvmActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.mvvm_activity_main); } public void get(View view){ getContributors("square", "retrofit"); } public void change(View view){ if(binding.getContributor() != null){ binding.getContributor().setLogin("zjutkz"); } } public void showProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.showMessage("正在加载..."); } public void dismissProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.dismiss(); } public void getContributors(String owner,String repo){ GitHubApi.getContributors(owner, repo) .take(1) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.newThread()) .map(new Func1<List<Contributor>, Contributor>() { @Override public Contributor call(List<Contributor> contributors) { return contributors.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层。

 
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="contributor" type="zjutkz.com.mvpdatabinding.viewmodel.Contributor"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/container" android:orientation="vertical" android:fitsSystemWindows="true"> <Button android:id="@+id/get" android:text="get" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="get"/> <Button android:id="@+id/change" android:text="change" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="change"/> <TextView 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}"/> </LinearLayout> </layout> public class MainActivity extends MvpActivity<ContributorView,ContributorPresenter> implements ContributorView { private ProcessDialog dialog; private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_main); } @NonNull @Override public ContributorPresenter createPresenter() { return new ContributorPresenter(); } public void get(View view){ getPresenter().get("square", "retrofit"); } public void change(View view){ if(binding.getContributor() != null){ binding.getContributor().setLogin("zjutkz"); } } @Override public void onLoadContributorStart() { showProgress(); } @Override public void onLoadContributorComplete(Contributor contributor) { binding.setContributor(contributor); dismissProgress(); } public void showProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.showMessage("正在加载..."); } public void dismissProgress(){ if(dialog == null){ dialog = new ProcessDialog(this); } dialog.dismiss(); } }

而后是presenter层

 
public class ContributorPresenter extends MvpBasePresenter<ContributorView> { private Subscriber<Contributor> contributorSub = new Subscriber<Contributor>() { @Override public void onStart() { ContributorView view = getView(); if(view != null){ view.onLoadContributorStart(); } } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Contributor topContributor) { ContributorView view = getView(); if(view != null){ view.onLoadContributorComplete(topContributor); } } }; public void get(String owner,String repo){ GitHubApi.getContributors(owner, repo) .take(1) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.newThread()) .map(new Func1<List<Contributor>, Contributor>() { @Override public Contributor call(List<Contributor> contributors) { return contributors.get(0); } }) .subscribe(contributorSub); } }

model层就是GithubApi等等。

咱们使用了data binding框架去节省了相似findViewById和数据绑定的时间,又使用了presenter去将业务逻辑和view层分离。

固然这也不是固定的,你大能够在viewmodel中实现相应的接口,presenter层的数据直接发送到viewmodel中,在viewmodel里更新,由于view和viewmodel是绑定的,这样view也会相应的做出反应。

说到这里,我仍是想重复刚才的那句话,最佳实践都是人想出来的,用这些框架根本的缘由也是为了尽可能低的耦合性和尽可能高的可复用性。

欢迎工做一到八年的Java工程师朋友们加入Java高级交流:854630135

本群提供免费的学习指导 架构资料 以及免费的解答

不懂得问题均可以在本群提出来 以后还会有直播平台和讲师直接交流噢

相关文章
相关标签/搜索