十分鐘上手MVC、MVP、MVVM
導(dǎo)讀
關(guān)于MVC、MVP、MVVM的具體概念和優(yōu)缺點網(wǎng)上有很多文章講解,這里不再贅述。
但是對于一個沒有實戰(zhàn)過這三種架構(gòu)模式的同學(xué)們,當(dāng)你辛辛苦苦花了幾個小時讀了關(guān)于這三種模式的文章,看了一些彼此分離沒有對比性的示例代碼。你們真的會很快上手這三種架構(gòu)模式的寫法嗎?
本文通過一個三合一demo,關(guān)鍵點代碼進(jìn)行注釋,十分鐘帶你入門。讓你分分鐘看懂三種模式的區(qū)別,快速上手三種寫法。
這是一個點擊按鈕,模擬耗時任務(wù)獲取數(shù)據(jù),然后設(shè)置Textview的demo。對,就是這么簡單,方便大家入門。

01
MVC

對于MVC模式,本demo只有兩個類:MvcMainActivity和GreetingGeneratorModel。
在MVC模式中,Activity就是Controller,同時也是View的一部分,它會調(diào)用Model層進(jìn)行數(shù)據(jù)獲取。Model層,封裝各種數(shù)據(jù)來源,和View層是直接通信的,它會調(diào)用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傳遞調(diào)用到Controller
15????????helloButton.setOnClickListener(new?View.OnClickListener()?{
16????????????@Override
17????????????public?void?onClick(View?view)?{
18????????????????//?(2)Controller直接調(diào)用Model層
19????????????????new?GreetingGeneratorModel("HelloWorld",?greetingTextView).execute();
20????????????}
21????????});
22????????//?(1)View傳遞調(diào)用到Controller
23????????goodbyeButtonClicked.setOnClickListener(new?View.OnClickListener()?{
24????????????@Override
25????????????public?void?onClick(View?view)?{
26????????????????//?(2)Controller直接調(diào)用Model層
27????????????????new?GreetingGeneratorModel("GoodBye",?greetingTextView).execute();
28????????????}
29????????});
30????}
31}
1//?Model層,封裝各種數(shù)據(jù)來源,和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????}
10
11????//?Simulates?computing?and?returns?a?random?integer
12????@Override
13????protected?Integer?doInBackground(Void...?params)?{
14????????try?{
15????????????//?Simulate?computing
16????????????Thread.sleep(2000);
17????????}?catch?(InterruptedException?e)?{
18????????}
19????????return?(int)?(Math.random()?*?100);
20????}
21
22????@Override
23????protected?void?onPostExecute(Integer?randomInt)?{
24????????//?(3)Model層調(diào)用View
25????????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模式講完啦,就是這么簡單,這也是大家初學(xué)Android時最常見的寫法。
02
MVP

在實現(xiàn)MVP模式寫法時,我們借助了Mosby這個開源庫。通過Mosby我們可以很輕松地實現(xiàn)MVP的寫法。
對于MVP模式,本demo有四個類:除了有MvpMainActivity和GreetingGeneratorModel外,新增了HelloWorldView和HelloWorldPresenter。

可以看到,相比于MVC模式,首先,HelloWorldView定義了操作View的接口。
1//?Mvp?View?接口,定義對View的操作接口
2public?interface?HelloWorldView?extends?MvpView?{
3????void?showHello(String?greetingText);
4
5????void?showGoodbye(String?greetingText);
6}
MvpMainActivity一方面要調(diào)用HelloWorldPresenter層進(jìn)行數(shù)據(jù)操作;另一方面要實現(xiàn)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????????????@Override
16????????????public?void?onClick(View?view)?{
17????????????????//?(1)調(diào)用Presenter層數(shù)據(jù)操作
18????????????????presenter.greetHello();
19????????????}
20????????});
21????????goodbyeButtonClicked.setOnClickListener(new?View.OnClickListener()?{
22????????????@Override
23????????????public?void?onClick(View?view)?{
24????????????????//?(1)調(diào)用Presenter層數(shù)據(jù)操作
25????????????????presenter.greetGoodbye();
26????????????}
27????????});
28????}
29
30????@Override
31????protected?void?onDestroy()?{
32????????super.onDestroy();
33????}
34
35????@NonNull
36????@Override
37????public?HelloWorldPresenter?createPresenter()?{
38????????return?new?HelloWorldPresenter();
39????}
40
41????//?實現(xiàn)Mvp?View?接口,具體對View的操作
42????@Override
43????public?void?showHello(String?greetingText)?{
44????????greetingTextView.setTextColor(Color.RED);
45????????greetingTextView.setText(greetingText);
46????}
47
48????//?實現(xiàn)Mvp?View?接口,具體對View的操作
49????@Override
50????public?void?showGoodbye(String?greetingText)?{
51????????greetingTextView.setTextColor(Color.BLUE);
52????????greetingTextView.setText(greetingText);
53????}
54}
GreetingGeneratorModel仍舊提供各種數(shù)據(jù)來源,但是要定義回調(diào)監(jiān)聽,對Presenter提供接口。
1//?Model層,封裝各種數(shù)據(jù)來源,對Prestener層提供接口
2public?class?GreetingGeneratorModel?extends?AsyncTask<Void,?Void,?Integer>?{
3????//?異步任務(wù)中要定義回調(diào)監(jiān)聽
4????public?interface?GreetingTaskListener?{
5????????public?void?onGreetingGenerated(String?greetingText);
6????}
7
8????private?String?baseText;
9????private?GreetingTaskListener?listener;
10
11????public?GreetingGeneratorModel(String?baseText,?GreetingTaskListener?listener)?{
12????????this.baseText?=?baseText;
13????????this.listener?=?listener;
14????}
15
16????//?Simulates?computing?and?returns?a?random?integer
17????@Override
18????protected?Integer?doInBackground(Void...?params)?{
19????????try?{
20????????????//?Simulate?computing
21????????????Thread.sleep(2000);
22????????}?catch?(InterruptedException?e)?{
23????????}
24????????return?(int)?(Math.random()?*?100);
25????}
26
27????@Override
28????protected?void?onPostExecute(Integer?randomInt)?{
29????????//?(3)執(zhí)行回調(diào)關(guān)聯(lián)到Presenter層
30????????listener.onGreetingGenerated(baseText?+?"?"?+?randomInt);
31????}
32}
HelloWorldPresenter既要調(diào)用Model層進(jìn)行數(shù)據(jù)獲取,也要實現(xiàn)GreetingGeneratorModel層的回調(diào)監(jiān)聽操作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????}
11
12????public?void?greetHello()?{
13????????cancelGreetingTaskIfRunning();
14????????//?實現(xiàn)Model層的回調(diào)監(jiān)聽
15????????greetingTask?=?new?GreetingGeneratorModel("HelloWorld",?new?GreetingGeneratorModel.GreetingTaskListener()?{
16????????????@Override
17????????????public?void?onGreetingGenerated(String?greetingText)?{
18????????????????//?(4)調(diào)用View層更新View
19????????????????if?(isViewAttached())
20????????????????????getView().showHello(greetingText);
21????????????}
22????????});
23????????//?(2)調(diào)用Model層獲取數(shù)據(jù)
24????????greetingTask.execute();
25????}
26
27????public?void?greetGoodbye()?{
28????????cancelGreetingTaskIfRunning();
29????????//?實現(xiàn)Model層的回調(diào)監(jiān)聽
30????????greetingTask?=?new?GreetingGeneratorModel("Goodbye",?new?GreetingGeneratorModel.GreetingTaskListener()?{
31????????????public?void?onGreetingGenerated(String?greetingText)?{
32????????????????//?(4)調(diào)用View層更新View
33????????????????if?(isViewAttached())
34????????????????????getView().showGoodbye(greetingText);
35????????????}
36????????});
37????????//?(2)調(diào)用Model層獲取數(shù)據(jù)
38????????greetingTask.execute();
39????}
40
41????//?Called?when?Activity?gets?destroyed,?so?cancel?running?background?task
42????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?=?true
4????}
然后對布局文件作出一定調(diào)整:根標(biāo)簽是layout,根標(biāo)簽之下增加了一個data標(biāo)簽,它包含兩個variable標(biāo)簽。
對于原先的Button按鈕通過@{handlers.onClickHello}進(jìn)行事件綁定前置操作。對于原先的Textview通過@{greetingGeneratorObj.baseText} 進(jìn)行數(shù)據(jù)綁定前置操作。
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????????<variable
10????????????name="greetingGeneratorObj"
11????????????type="com.example.architecturalpatterndemo.mvvm.GreetingGeneratorObj"?/>
12????data>
13
14????<LinearLayout
15????????android:layout_width="match_parent"
16????????android:layout_height="match_parent"
17????????android:orientation="vertical">
18
19????????<TextView
20????????????android:id="@+id/greetingTextView"
21????????????android:layout_width="wrap_content"
22????????????android:layout_height="wrap_content"
23????????????android:text="@{greetingGeneratorObj.baseText}"?/>
24
25????????<Button
26????????????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"?/>
31
32????????<Button
33????????????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>
39layout>

在MVVM模式中,本demo有四個類:除了MvvmMainActivity和GreetingGeneratorModel外,新增了GreetingGeneratorObj數(shù)據(jù)對象類和MyHandlers綁定方法類。

在MvvmMainActivity中,通過ActivityMvvmmainBinding對象的setHandlers方法進(jìn)行事件綁定,可以看到,setOnClickListener代碼消失了;
通過ActivityMvvmmainBinding對象的setGreetingGeneratorObj方法進(jìn)行數(shù)據(jù)綁定。具體雙向數(shù)據(jù)綁定是怎么執(zhí)行的,都由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)按套路寫好數(shù)據(jù)綁定,具體怎么實現(xiàn)雙向數(shù)據(jù)綁定,都由DataBinding框架來完成
9????????//?數(shù)據(jù)綁定
10????????binding.setGreetingGeneratorObj(greetingGeneratorObj);
11????????//?事件綁定
12????????binding.setHandlers(new?MyHandlers(greetingGeneratorObj));
13????}
14
15}
1//?Model層,封裝各種數(shù)據(jù)來源
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????}
10
11????//?Simulates?computing?and?returns?a?random?integer
12????@Override
13????protected?Integer?doInBackground(Void...?params)?{
14????????try?{
15????????????//?Simulate?computing
16????????????Thread.sleep(2000);
17????????}?catch?(InterruptedException?e)?{
18????????}
19
20????????return?(int)?(Math.random()?*?100);
21????}
22
23????@Override
24????protected?void?onPostExecute(Integer?randomInt)?{
25????????//?(3)ViewModel層調(diào)用ViewModel層
26????????greetingGeneratorObj.setBaseText(baseText?+?randomInt);
27????}
28}
數(shù)據(jù)對象的set方法需要增加notifyPropertyChanged方法。
1//?數(shù)據(jù)對象類
2public?class?GreetingGeneratorObj?extends?BaseObservable?{
3????public?static?String?baseText;
4
5????public?GreetingGeneratorObj(String?baseText)?{
6????????this.baseText?=?baseText;
7????}
8
9????@Bindable
10????public?String?getBaseText()?{
11????????return?baseText;
12????}
13
14????public?void?setBaseText(String?baseText)?{
15????????GreetingGeneratorObj.baseText?=?baseText;
16????????notifyPropertyChanged(BR.baseText);
17????}
18}
MyHandlers中實現(xiàn)操作Model的方法,這些方法與xml中布局文件是對應(yīng)的,會被DataBinding框架自動調(diào)用。
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層調(diào)用Model層
10????????new?GreetingGeneratorModel("HelloWorld",?greetingGeneratorObj).execute();
11????}
12
13????public?void?onClickGoodbye(View?view)?{
14????????//?(2)ViewModel層調(diào)用Model層
15????????new?GreetingGeneratorModel("GoodBye",?greetingGeneratorObj).execute();
16????}
17}
04
demo地址
以上就是本demo的全部啦。通過關(guān)系圖和關(guān)鍵代碼注釋,使用三種模式實現(xiàn)同樣的小功能,這樣能很清楚地對比。十分鐘上手三種模式的寫法!具體demo地址如下:
https://github.com/youjinjin/ArchitecturalPatternDemo
