

本文字数:2216字
预计阅读时间:15分钟
导读
关于MVC、MVP、MVVM的具体概念和优缺点网上有很多文章讲解,这里不再赘述。
但是对于一个没有实战过这三种架构模式的同学们,当你辛辛苦苦花了几个小时读了关于这三种模式的文章,看了一些彼此分离没有对比性的示例代码。你们真的会很快上手这三种架构模式的写法吗?
本文通过一个三合一demo,关键点代码进行注释,十分钟带你入门。让你分分钟看懂三种模式的区别,快速上手三种写法。
这是一个点击按钮,模拟耗时任务获取数据,然后设置Textview的demo。对,就是这么简单,方便大家入门。

01
MVC

对于MVC模式,本demo只有两个类:MvcMainActivity和GreetingGeneratorModel。
在MVC模式中,Activity就是Controller,同时也是View的一部分,它会调用Model层进行数据获取。Model层,封装各种数据来源,和View层是直接通信的,它会调用View层里的更新View方法。

1// Activity即是Controller,同时也是View的一部分 2public class MvcMainActivity extends AppCompatActivity { 3 TextView greetingTextView; 4 Button helloButton; 5 Button goodbyeButtonClicked; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState);10 setContentView(R.layout.activity_mvcmain);11 greetingTextView = findViewById(R.id.greetingTextView);12 helloButton = findViewById(R.id.helloButton);13 goodbyeButtonClicked = findViewById(R.id.goodbyeButtonClicked);14 // (1)View传递调用到Controller15 helloButton.setOnClickListener(new View.OnClickListener() {16 @Override17 public void onClick(View view) {18 // (2)Controller直接调用Model层19 new GreetingGeneratorModel("HelloWorld", greetingTextView).execute();20 }21 });22 // (1)View传递调用到Controller23 goodbyeButtonClicked.setOnClickListener(new View.OnClickListener() {24 @Override25 public void onClick(View view) {26 // (2)Controller直接调用Model层27 new GreetingGeneratorModel("GoodBye", greetingTextView).execute();28 }29 });30 }31}
1// Model层,封装各种数据来源,和View层是直接通信的 2public class GreetingGeneratorModel extends AsyncTask<Void, Void, Integer> { 3 private String baseText; 4 private TextView greetingTextView; 5 6 public GreetingGeneratorModel(String baseText, TextView greetingTextView) { 7 this.baseText = baseText; 8 this.greetingTextView = greetingTextView; 9 }1011 // Simulates computing and returns a random integer12 @Override13 protected Integer doInBackground(Void... params) {14 try {15 // Simulate computing16 Thread.sleep(2000);17 } catch (InterruptedException e) {18 }19 return (int) (Math.random() * 100);20 }2122 @Override23 protected void onPostExecute(Integer randomInt) {24 // (3)Model层调用View25 if ("HelloWorld".equals(baseText)) {26 greetingTextView.setTextColor(Color.RED);27 } else {28 greetingTextView.setTextColor(Color.BLUE);29 }30 greetingTextView.setText(baseText + randomInt);31 }32}
好啦。MVC模式讲完啦,就是这么简单,这也是大家初学Android时最常见的写法。
02
MVP

在实现MVP模式写法时,我们借助了Mosby这个开源库。通过Mosby我们可以很轻松地实现MVP的写法。
对于MVP模式,本demo有四个类:除了有MvpMainActivity和GreetingGeneratorModel外,新增了HelloWorldView和HelloWorldPresenter。

可以看到,相比于MVC模式,首先,HelloWorldView定义了操作View的接口。
1// Mvp View 接口,定义对View的操作接口2public interface HelloWorldView extends MvpView {3 void showHello(String greetingText);45 void showGoodbye(String greetingText);6}
MvpMainActivity一方面要调用HelloWorldPresenter层进行数据操作;另一方面要实现HelloWorldView中具体操作View的接口。
1// View层,视图层 2public class MvpMainActivity extends MvpActivity<HelloWorldView, HelloWorldPresenter> implements HelloWorldView { 3 TextView greetingTextView; 4 Button helloButton; 5 Button goodbyeButtonClicked; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState);10 setContentView(R.layout.activity_mvpmain);11 greetingTextView = findViewById(R.id.greetingTextView);12 helloButton = findViewById(R.id.helloButton);13 goodbyeButtonClicked = findViewById(R.id.goodbyeButtonClicked);14 helloButton.setOnClickListener(new View.OnClickListener() {15 @Override16 public void onClick(View view) {17 // (1)调用Presenter层数据操作18 presenter.greetHello();19 }20 });21 goodbyeButtonClicked.setOnClickListener(new View.OnClickListener() {22 @Override23 public void onClick(View view) {24 // (1)调用Presenter层数据操作25 presenter.greetGoodbye();26 }27 });28 }2930 @Override31 protected void onDestroy() {32 super.onDestroy();33 }3435 @NonNull36 @Override37 public HelloWorldPresenter createPresenter() {38 return new HelloWorldPresenter();39 }4041 // 实现Mvp View 接口,具体对View的操作42 @Override43 public void showHello(String greetingText) {44 greetingTextView.setTextColor(Color.RED);45 greetingTextView.setText(greetingText);46 }4748 // 实现Mvp View 接口,具体对View的操作49 @Override50 public void showGoodbye(String greetingText) {51 greetingTextView.setTextColor(Color.BLUE);52 greetingTextView.setText(greetingText);53 }54}
GreetingGeneratorModel仍旧提供各种数据来源,但是要定义回调监听,对Presenter提供接口。
1// Model层,封装各种数据来源,对Prestener层提供接口 2public class GreetingGeneratorModel extends AsyncTask<Void, Void, Integer> { 3 // 异步任务中要定义回调监听 4 public interface GreetingTaskListener { 5 public void onGreetingGenerated(String greetingText); 6 } 7 8 private String baseText; 9 private GreetingTaskListener listener;1011 public GreetingGeneratorModel(String baseText, GreetingTaskListener listener) {12 this.baseText = baseText;13 this.listener = listener;14 }1516 // Simulates computing and returns a random integer17 @Override18 protected Integer doInBackground(Void... params) {19 try {20 // Simulate computing21 Thread.sleep(2000);22 } catch (InterruptedException e) {23 }24 return (int) (Math.random() * 100);25 }2627 @Override28 protected void onPostExecute(Integer randomInt) {29 // (3)执行回调关联到Presenter层30 listener.onGreetingGenerated(baseText + " " + randomInt);31 }32}
HelloWorldPresenter既要调用Model层进行数据获取,也要实现GreetingGeneratorModel层的回调监听操作View层更新View。
1// Presenter层,逻辑控制层 2public class HelloWorldPresenter extends MvpBasePresenter<HelloWorldView> { 3 // Greeting Task is "business logic" 4 private GreetingGeneratorModel greetingTask; 5 6 private void cancelGreetingTaskIfRunning() { 7 if (greetingTask != null) { 8 greetingTask.cancel(true); 9 }10 }1112 public void greetHello() {13 cancelGreetingTaskIfRunning();14 // 实现Model层的回调监听15 greetingTask = new GreetingGeneratorModel("HelloWorld", new GreetingGeneratorModel.GreetingTaskListener() {16 @Override17 public void onGreetingGenerated(String greetingText) {18 // (4)调用View层更新View19 if (isViewAttached())20 getView().showHello(greetingText);21 }22 });23 // (2)调用Model层获取数据24 greetingTask.execute();25 }2627 public void greetGoodbye() {28 cancelGreetingTaskIfRunning();29 // 实现Model层的回调监听30 greetingTask = new GreetingGeneratorModel("Goodbye", new GreetingGeneratorModel.GreetingTaskListener() {31 public void onGreetingGenerated(String greetingText) {32 // (4)调用View层更新View33 if (isViewAttached())34 getView().showGoodbye(greetingText);35 }36 });37 // (2)调用Model层获取数据38 greetingTask.execute();39 }4041 // Called when Activity gets destroyed, so cancel running background task42 public void detachView(boolean retainPresenterInstance) {43 super.detachView(retainPresenterInstance);44 if (!retainPresenterInstance) {45 cancelGreetingTaskIfRunning();46 }47 }48}
03
MVVM
要使用MVVM模式,首先你需要在app下的buld.gradle中添加DataBinding框架配置:
1 // DataBinding配置2 dataBinding {3 enabled = true4 }
然后对布局文件作出一定调整:根标签是layout,根标签之下增加了一个data标签,它包含两个variable标签。
对于原先的Button按钮通过@{handlers.onClickHello}进行事件绑定前置操作。对于原先的Textview通过@{greetingGeneratorObj.baseText} 进行数据绑定前置操作。
1<layout xmlns:android="http://schemas.android.com/apk/res/android"> 2 3 <data> 4 5 <variable 6 name="handlers" 7 type="com.example.architecturalpatterndemo.mvvm.MyHandlers" /> 8 9 <variable10 name="greetingGeneratorObj"11 type="com.example.architecturalpatterndemo.mvvm.GreetingGeneratorObj" />12 </data>1314 <LinearLayout15 android:layout_width="match_parent"16 android:layout_height="match_parent"17 android:orientation="vertical">1819 <TextView20 android:id="@+id/greetingTextView"21 android:layout_width="wrap_content"22 android:layout_height="wrap_content"23 android:text="@{greetingGeneratorObj.baseText}" />2425 <Button26 android:id="@+id/helloButton"27 android:layout_width="wrap_content"28 android:layout_height="wrap_content"29 android:onClick="@{handlers.onClickHello}"30 android:text="hello" />3132 <Button33 android:id="@+id/goodbyeButtonClicked"34 android:layout_width="wrap_content"35 android:layout_height="wrap_content"36 android:onClick="@{handlers.onClickGoodbye}"37 android:text="Good bye" />38 </LinearLayout>39</layout>

在MVVM模式中,本demo有四个类:除了MvvmMainActivity和GreetingGeneratorModel外,新增了GreetingGeneratorObj数据对象类和MyHandlers绑定方法类。

在MvvmMainActivity中,通过ActivityMvvmmainBinding对象的setHandlers方法进行事件绑定,可以看到,setOnClickListener代码消失了;
通过ActivityMvvmmainBinding对象的setGreetingGeneratorObj方法进行数据绑定。具体双向数据绑定是怎么执行的,都由DataBinding框架来完成。
1public class MvvmMainActivity extends AppCompatActivity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 ActivityMvvmmainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvmmain); 7 GreetingGeneratorObj greetingGeneratorObj = new GreetingGeneratorObj(""); 8 // (1)按套路写好数据绑定,具体怎么实现双向数据绑定,都由DataBinding框架来完成 9 // 数据绑定10 binding.setGreetingGeneratorObj(greetingGeneratorObj);11 // 事件绑定12 binding.setHandlers(new MyHandlers(greetingGeneratorObj));13 }1415}
1// Model层,封装各种数据来源 2public class GreetingGeneratorModel extends AsyncTask<Void, Void, Integer> { 3 private String baseText; 4 private GreetingGeneratorObj greetingGeneratorObj; 5 6 public GreetingGeneratorModel(String baseText, GreetingGeneratorObj greetingGeneratorObj) { 7 this.baseText = baseText; 8 this.greetingGeneratorObj = greetingGeneratorObj; 9 }1011 // Simulates computing and returns a random integer12 @Override13 protected Integer doInBackground(Void... params) {14 try {15 // Simulate computing16 Thread.sleep(2000);17 } catch (InterruptedException e) {18 }1920 return (int) (Math.random() * 100);21 }2223 @Override24 protected void onPostExecute(Integer randomInt) {25 // (3)ViewModel层调用ViewModel层26 greetingGeneratorObj.setBaseText(baseText + randomInt);27 }28}
数据对象的set方法需要增加notifyPropertyChanged方法。
1// 数据对象类 2public class GreetingGeneratorObj extends BaseObservable { 3 public static String baseText; 4 5 public GreetingGeneratorObj(String baseText) { 6 this.baseText = baseText; 7 } 8 9 @Bindable10 public String getBaseText() {11 return baseText;12 }1314 public void setBaseText(String baseText) {15 GreetingGeneratorObj.baseText = baseText;16 notifyPropertyChanged(BR.baseText);17 }18}
MyHandlers中实现操作Model的方法,这些方法与xml中布局文件是对应的,会被DataBinding框架自动调用。
1public class MyHandlers { 2 private GreetingGeneratorObj greetingGeneratorObj; 3 4 public MyHandlers(GreetingGeneratorObj greetingGeneratorObj) { 5 this.greetingGeneratorObj = greetingGeneratorObj; 6 } 7 8 public void onClickHello(View view) { 9 // (2)ViewModel层调用Model层10 new GreetingGeneratorModel("HelloWorld", greetingGeneratorObj).execute();11 }1213 public void onClickGoodbye(View view) {14 // (2)ViewModel层调用Model层15 new GreetingGeneratorModel("GoodBye", greetingGeneratorObj).execute();16 }17}
04
demo地址
以上就是本demo的全部啦。通过关系图和关键代码注释,使用三种模式实现同样的小功能,这样能很清楚地对比。十分钟上手三种模式的写法!具体demo地址如下:
https://github.com/youjinjin/ArchitecturalPatternDemo
也许你还想看
(▼点击文章标题或封面查看)
2019-08-15
2019-10-17
2019-09-26
加入搜狐技术作者天团
千元稿费等你来!
戳这里!☛
欢迎留言讨论 !
▼▼▼