MVC煮甥、MVP盗温、MVVM,作為Android開發(fā)中重要的三種框架模式成肘,能夠理解并能較好地將其運用在自己的項目中是很重要的卖局。本文主要是自己對Android中這三種框架模式的學習總結,其中重點介紹了MVP模式双霍,如有錯誤或者表達不當之處砚偶,歡迎指出。
一洒闸、概述
二染坯、MVC
三、MVP
1.簡介
2.示例
3.改進
四顷蟀、MVVM
五酒请、參考
一、概述
設計模式是一套被反復使用的鸣个、多數(shù)人知曉的羞反、經過分類編目的、代碼設計經驗的總結囤萤。常見的有單例模式昼窗,適配器模式,代理模式等等涛舍。MVC澄惊,MVP等等不屬于設計模式,而是框架模式富雅,那么框架模式與設計模式的區(qū)別是什么呢掸驱。
簡單來說,框架模式是一種思想没佑,框架是框架模式的具體實現(xiàn)毕贼,是對代碼的重用,而設計模式是設計重用蛤奢。設計模式是對在某種環(huán)境中反復出現(xiàn)的問題以及解決該問題的方案的描述鬼癣,它比框架更抽象陶贼;框架可以用代碼表示,也能直接執(zhí)行或復用待秃,而對模式而言只有實例才能用代碼表示;設計模式是比框架更小的元素拜秧,一個框架中往往含有一個或多個設計模式,框架總是針對某一特定應用領域章郁,但同一模式卻可適用于各種應用枉氮。可以說驱犹,框架是軟件嘲恍,而設計模式是軟件的知識。
二雄驹、MVC
MVC全稱是Model-View-Controller佃牛,即模型-視圖-控制器,它用一種業(yè)務邏輯医舆、數(shù)據(jù)俘侠、界面顯示分離的方法組織代碼,將業(yè)務邏輯聚集到一個部件里面蔬将,在改進和個性化定制界面及用戶交互的同時爷速,不需要重新編寫業(yè)務邏輯。MVC三部分具體如下:
Model(模型)是應用程序中用于處理應用程序數(shù)據(jù)邏輯的部分霞怀”苟
通常模型對象負責從網絡中或者在數(shù)據(jù)庫中存取數(shù)據(jù)。View(視圖)是應用程序中處理數(shù)據(jù)顯示的部分毙石×冢
通常視圖是依據(jù)模型數(shù)據(jù)創(chuàng)建的。Controller(控制器)是應用程序中處理用戶交互的部分徐矩≈褪保
通常控制器負責從視圖讀取數(shù)據(jù)滤灯,控制用戶輸入坪稽,并向模型發(fā)送數(shù)據(jù)。
MVC的目的主要是將數(shù)據(jù)模型和視圖分離開鳞骤,并以控制器作為連接二者的橋梁以實現(xiàn)解耦窒百,下面這張圖很清楚地展示了整體結構:
在Android開發(fā)中,MVC的應用比較經典豫尽,比如layout文件夾下的各種布局文件就對應于view層贝咙,從網絡或者數(shù)據(jù)庫獲取數(shù)據(jù)就對應于model層,controller層就是各種activity拂募。
三庭猩、MVP
MVP,全稱是Model-View-Presenter陈症,它針對MVC做了一些改進蔼水,解除了Android中View和Model的耦合,使得寫出的代碼邏輯更加清晰录肯,可擴展性更好趴腋。
簡介
在Android中,傳統(tǒng)的MVC中的View论咏,對應的是各種Layout布局文件优炬,但是這些布局文件中并不像Web端那樣強大,能做的事情非常有限厅贪。Controller對應的是Activity蠢护,但是在實際的項目中也會有很多UI操作在這一層,做了很多View中應該做的事情养涮,當然Controller中也包含Controller應該做的事情葵硕,比如各種事件的派發(fā)回調,而且在一層中我們會根據(jù)事件再去調用Model層操作數(shù)據(jù)贯吓,所以這種MVC的方式在實際項目中懈凹,Activity所在的Controller是非常重的,各層次之間的耦合情況也比較嚴重悄谐,不方便單元測試介评。
MVC的進化版——MVP把Layout布局和Activity作為View層,增加了Presenter爬舰,Presenter層與Model層進行業(yè)務的交互们陆,完成后再與View層交互(也就是Activity)進行回調來刷新UI。這樣一來洼专,所有業(yè)務邏輯的工作都交給了Presenter中進行棒掠,使得View層與Model層的耦合度降低,Activity中的工作也進行了簡化屁商。下面通過一個簡單的例子來展示一些它的用法烟很,當然想要靈活地掌握MVP這種框架模式還是需要不斷地實踐的。
示例
在這個例子中蜡镶,我們的主要功能是在一個Activity中獲取新聞數(shù)據(jù)雾袱,并將其展示在頁面上,下面是幾部分主要的代碼官还。
- Model層
1芹橡、接口NewsModel
public interface NewsModel {
//給定新聞數(shù)據(jù)的url獲取數(shù)據(jù)
void getNewsFromNet(String url, NewsModelImpl.NewsCallBack newsCallBack);
}
2、NewsModelImpl實現(xiàn)數(shù)據(jù)獲取
public class NewsModelImpl implements NewsModel {
private String newsData;
@Override
public void getNewsFromNet(final String url, final NewsCallBack newsCallBack) {
//模擬獲取數(shù)據(jù)耗時操作
new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//模擬從url獲取數(shù)據(jù)
newsData = url + "湄公河票房突破十億 1天前";
newsCallBack.onSuccess(newsData);
}
}.start();
}
public interface NewsCallBack {
void onSuccess(String mNewsData);
}
}
- Presenter層
public class NewsPresenter {
//View的引用
private NewsView mNewsView;
//Model的引用
private NewsModel mNewsModel = new NewsModelImpl();
private Handler handler = new Handler();
public NewsPresenter(NewsView mNewsView) {
this.mNewsView = mNewsView;
}
public void getNewsData() {
mNewsView.showLoading();
mNewsModel.getNewsFromNet("", new NewsModelImpl.NewsCallBack() {
@Override
public void onSuccess(final String mNewsData) {
handler.post(new Runnable() {
@Override
public void run() {
mNewsView.displayNews(mNewsData);
mNewsView.dismissLoading();
}
});
}
});
}
}
- View層
1望伦、邏輯抽象
public interface NewsView {
//加載中
void showLoading();
//展示新聞
void displayNews(String newsData);
//取消加載
void dismissLoading();
//加載失敗
void displayFailing();
}
2林说、具體實現(xiàn)
public class NewsActivity extends AppCompatActivity implements NewsView {
private TextView tvData;
private String data;
private ProgressDialog progressDialog;
private NewsPresenter newsPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvData = (TextView) findViewById(R.id.tv_data);
newsPresenter = new NewsPresenter(this);
newsPresenter.getNewsData();
}
@Override
public void showLoading() {
progressDialog = ProgressDialog.show(this, "請稍候", "數(shù)據(jù)正在加載中", true, false);
progressDialog.show();
}
@Override
public void displayNews(String newsData) {
data = newsData;
tvData.setText(data);
}
@Override
public void dismissLoading() {
progressDialog.dismiss();
}
@Override
public void displayFailing() {
Toast.makeText(this, "加載失敗", Toast.LENGTH_SHORT).show();
}
}
上面代碼的主要邏輯如下:
1煎殷、Model層主要是數(shù)據(jù)獲取,我們定義了接口NewsModel腿箩,并在NewsModelImpl中實現(xiàn)數(shù)據(jù)獲取豪直,注意這里回調機制的用法。
2珠移、View層的話我們先定義接口NewsView弓乙,抽象出通用的方法。
3钧惧、Presenter層的話暇韧,作為Model和View的橋梁,持有NewsModel和NewsView的引用浓瞪,NewsPresenter主要完成業(yè)務邏輯的處理懈玻。
4、最后我們再看下NewsActivity追逮,實現(xiàn)了接口NewsView酪刀,并在onCreate()方法里通過newsPresenter = new NewsPresenter(this);將自身傳遞給NewsPresenter建立引用,這樣M钮孵、V骂倘、P三者的聯(lián)系就建立起來了。
改進
上面的三部分代碼給出了MVP模式的一個典型的例子巴席,但是還是存在一定的問題的历涝。考慮如下:在上面的NewsPresenter中主要是一些業(yè)務邏輯的處理漾唉,其中getNewsData()是一個較為耗時的操作荧库,因為NewsPresenter持有了對NewsActivity的強引用,如果在請求結束之前NewsActivity被銷毀了赵刑,因為網絡請求還沒有返回分衫,導致NewsPresenter一直持有NewsActivity對象,使得NewsActivity對象無法被回收般此,發(fā)生內存泄漏蚪战。解決方法主要是** 對presenter和view層進行修改 **。在上面代碼的基礎上铐懊,我們做出下面的修改邀桑。
-
添加BasePresenter
BasePresenter主要是建立Presenter和View之間的聯(lián)系,方便控制二者的關系科乎。
public abstract class BasePresenter<T> {
private Reference<T> mViewReference;
//建立關聯(lián)
public void attachView(T view) {
mViewReference = new WeakReference<>(view);
}
//獲取關聯(lián)
protected T getView() {
return mViewReference.get();
}
//是否關聯(lián)
public boolean isViewAttached() {
return mViewReference != null && mViewReference.get() != null;
}
//解除關聯(lián)
public void detachView() {
if (mViewReference != null) {
mViewReference.clear();
mViewReference = null;
}
}
}
- 修改NewsPresenter 使其繼承自BasePresenter
public class NewsPresenter extends BasePresenter<NewsView> {
private NewsModel mNewsModel;
private Handler handler;
public NewsPresenter() {
this.mNewsModel = new NewsModelImpl();
this.handler= new Handler();
}
public void getNewsData() {
//getView()獲取已經關聯(lián)的View
getView().showLoading();
mNewsModel.getNewsFromNet("", new NewsModelImpl.NewsCallBack() {
@Override
public void onSuccess(final String mNewsData) {
handler.post(new Runnable() {
@Override
public void run() {
getView().displayNews(mNewsData);
getView().dismissLoading();
}
});
}
});
}
}
-
添加BaseActivity
在onCreate()里將View與Presenter關聯(lián)壁畸,onDestroy()里解除關聯(lián)。
public abstract class BaseActivity<V, T extends BasePresenter<V>> extends AppCompatActivity {
protected T mPresenter;
@SuppressWarnings("unchecked")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = setPresenter();
mPresenter.attachView((V) this);
}
@Override
protected void onDestroy() {
super.onDestroy();
mPresenter.detachView();
}
protected abstract T setPresenter();
}
- 最后是修改后的NewsActivity
public class NewsActivity extends BaseActivity<NewsView, NewsPresenter> implements NewsView {
private TextView tvData;
private String data;
private ProgressDialog progressDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvData = (TextView) findViewById(R.id.tv_data);
mPresenter.getNewsData();
}
@Override
public void showLoading() {
progressDialog = ProgressDialog.show(this, "請稍候", "數(shù)據(jù)正在加載中", true, false);
progressDialog.show();
}
@Override
public void displayNews(String newsData) {
data = newsData;
tvData.setText(data);
}
@Override
public void dismissLoading() {
progressDialog.dismiss();
}
@Override
public void displayFailing() {
Toast.makeText(this, "加載失敗", Toast.LENGTH_SHORT).show();
}
@Override
protected NewsPresenter setPresenter() {
return new NewsPresenter();
}
}
到這里,MVP的部分介紹就結束了捏萍。MVP是開發(fā)過程中比較好的框架模式太抓,它能夠將各個組件進行解耦,并且?guī)砹己玫目蓴U展性照弥、可測試性腻异、穩(wěn)定性、可維護性这揣,同時使得每個類型的職責相對單一、簡單影斑,有效地將業(yè)務邏輯和數(shù)據(jù)處理等工作從Activity里抽離出來给赞,使得每個類盡可能簡單。
四矫户、MVVM
MVVM與MVP非常相似片迅,唯一的區(qū)別在于View和Model進行雙向綁定,兩者之間有一方發(fā)生變化則會反應到另一方上皆辽。MVP中的View更新需要通過Presenter柑蛇。Android中的ListView、Adapter以及數(shù)據(jù)之間的關系就像MVVM驱闷,其中Adapter就是ViewModel角色耻台,它與View進行了綁定,又與數(shù)據(jù)集進行了綁定空另,當數(shù)據(jù)集合發(fā)生變化時盆耽,調用Adapter的notifyDataSetChanged之后View就直接更新,它們之間沒有直接的耦合扼菠,使得ListView變得更為靈活摄杂。
五、參考
到這里循榆,關于常見的幾種框架模式就介紹完了析恢,這里也只是自己的初步學習總結,在之后的開發(fā)實踐中會繼續(xù)完善秧饮,爭取帶來更完善的總結與思考映挂。
相關參考:
1、何紅輝 《Android源碼設計模式 解析與實戰(zhàn)》
2浦楣、MVP框架Mosby架構詳解
3袖肥、Hongyang - 淺談 MVP in Android