編輯:關於Android編程
關於架構的文章,博主很早就想寫了,雖說最近比較流行MVVM,但是MVP以及MVC也沒有過時之說,最主要還是要根據業務來選擇合適的架構。當然現在寫MVP的文章很多,也有很多好的文章,但是大多數看完後還是一頭霧水,用最少的文字表述清楚是我一貫的風格(這裡小小的裝逼一下),所以還是自己總結比較靠譜。
講到MVP前我們有必要回顧下MVC,MVC(Model-View-Controller,模型-視圖-控制器)模式是80年代Smalltalk-80出現的一種軟件設計模式,後來得到了廣泛的應用,用一種業務邏輯、數據、界面顯示分離的方法組織代碼,在改進和個性化定制界面及用戶交互的同時,不需要重新編寫業務邏輯。
Android中界面部分也可以采用了MVC框架,MVC的角色定義分別為:
模型層(Model)
我們針對業務模型,建立的數據結構和相關的類,就可以理解為Model,Model是與View無關,而與業務相關的。
視圖層(View)
一般采用xml文件或者java代碼進行界面的描述,也可以使用javascript+html等的方式作為view層。
控制層(controller)
android的控制層通常在acitvity、Fragment或者由它們控制的其他業務類中。
在Android開發中,Activity並不是一個標准的MVC模式中的Controller,它的首要職責是加載應用的布局和初始化用戶界面,並接受並處理來自用戶的操作請求,進而作出響應。隨著界面及其邏輯的復雜度不斷提升,Activity類的職責不斷增加,以致變得龐大臃腫。
MVP(Model View Presenter)是MVC的演化版本,MVP的角色定義分別為:
Presenter
作為View和Model的溝通的橋梁,它從Model層檢索數據後返回給View層,使得View和Model之間沒有耦合。
Model
主要提供數據的存取功能。Presenter需要通過Model層來存儲、獲取數據。
View
負責處理用戶事件和視圖部分的展示。在Android中,它可能是Activity、Fragment類或者是某個View控件。

在MVP裡,Presenter完全把Model和View進行了分離,主要的程序邏輯在Presenter裡實現。而且,Presenter與具體的View是沒有直接關聯的,而是通過定義好的接口進行交互,從而使得在變更View時候可以保持Presenter的不變。 View只應該有簡單的Set/Get的方法,用戶輸入和設置界面顯示的內容,除此就不應該有更多的內容,絕不容許直接訪問Model,這就是與MVC很大的不同之處。
這裡我們舉個例子,通過網絡獲取文章的標題和內容並顯示在界面上,訪問網絡的內容和Android網絡編程(三)Volley用法全解析這篇文章所采用的數據是一樣的,Json數據格式請點擊這裡。
訪問網絡數據用的是OkHttpFinal,包目錄如下圖所示:

首先我們要創建bean文件,這裡帖上部分代碼:
public class ArticleInfo {
private String desc;
private String status;
private List detail = new ArrayList();
public List getDetail() {
return detail;
}
public void setDetail(List detail) {
this.detail = detail;
}
...省略
public class detail {
private String title;
private String article_url;
private String my_abstract;
private String article_type;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
...省略
}
接下來是獲取文章的Model接口類,這個接口用來定義如何獲取數據:
public interface ArticleModel {
void getArtcle(OnArticleListener onArticleListener);
}
裡面有一個回調監聽接口,裡面定義了網絡訪問回調的各種狀態:
public interface OnArticleListener {
void onSuccess(ArticleInfo articleInfo);
void onStart();
void onFailed();
void onFinish();
}
接下來我們寫ArticleModel的實現類用來獲取數據:
public class ArticleModelImpl implements ArticleModel {
@Override
public void getArtcle(final OnArticleListener onArticleListener) {
HttpRequest.post("http://api.1-blog.com/biz/bizserver/article/list.do",new BaseHttpRequestCallback(){
@Override
protected void onSuccess(ArticleInfo articleInfo) {
super.onStart();
onArticleListener.onSuccess(articleInfo);
}
@Override
public void onStart() {
super.onStart();
onArticleListener.onStart();
}
@Override
public void onFailure(int errorCode, String msg) {
super.onFailure(errorCode, msg);
onArticleListener.onFailed();
}
@Override
public void onFinish() {
super.onFinish();
onArticleListener.onFinish();
}
});
}
}
通過OkHttpFinal來獲取數據,同時在回調函數中調用自己定義的回調函數。
首先定義ArticlePresenter接口:
public interface ArticlePresenter {
void getArticle();
}
實現ArticlePresenter接口:
public class ArticlePresenterImpl implements ArticlePresenter, OnArticleListener {
private ArticleView mArticleView;
private ArticleModel mArticleModel;
public ArticlePresenterImpl(ArticleView mArticleView) {
this.mArticleView = mArticleView;
mArticleModel = new ArticleModelImpl();
}
@Override
public void getArticle() {
mArticleModel.getArtcle(this);
}
@Override
public void onSuccess(ArticleInfo articleInfo) {
mArticleView.setArticleInfo(articleInfo);
}
@Override
public void onStart() {
mArticleView.showLoading();
}
@Override
public void onFailed() {
mArticleView.showError();
}
@Override
public void onFinish() {
mArticleView.hideLoading();
}
}
很明顯ArticlePresenterImpl 中含有ArticleModel 和ArticleView的實例(後面會講),通過實現OnArticleListener接口並調用ArticleModel 來獲取數據並回調給自身,最後通過ArticleView來和Activity進行交互,來更改界面。這回我們應該明白了,Presenter就是一個中間人的角色,他通過Model來獲得並保存數據,然後在通過View來更新界面。這期間通過定義接口使得View和Model沒有任何交互。最後來看看View層的實現:
ArticleView用來定義界面交互的方法:
public interface ArticleView {
void setArticleInfo(ArticleInfo articleInfo);
void showLoading();
void hideLoading();
void showError();
}
我們在Activity中來調用ArticlePresenterImpl:
public class MainActivity extends BaseActivity implements ArticleView{
private Button bt_getarticle;
private TextView tv_article_title;
private TextView tv_article_content;
private ArticlePresenter mArticlePresenter;
private Dialog mDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mArticlePresenter=new ArticlePresenterImpl(this);
mDialog=new ProgressDialog(this);
mDialog.setTitle("獲取數據中");
bt_getarticle = findView(R.id.bt_getarticle);
tv_article_title = findView(R.id.tv_article_title);
tv_article_content = findView(R.id.tv_article_content);
bt_getarticle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mArticlePresenter.getArticle();
}
});
}
@Override
public void setArticleInfo(ArticleInfo articleInfo) {
if(null!=articleInfo) {
List list = articleInfo.getDetail();
if(null!=list&&list.size()>1)
tv_article_title.setText(list.get(1).getTitle());
tv_article_content.setText(list.get(1).getMy_abstract());
}
}
@Override
public void showLoading() {
mDialog.show();
}
@Override
public void hideLoading() {
if(mDialog.isShowing()) {
mDialog.dismiss();
}
}
@Override
public void showError() {
Toast.makeText(getApplicationContext(),"網絡出錯",Toast.LENGTH_SHORT).show();
}
}
需要注意的是MainActivity實現了ArticleView接口,用來接收回調更新界面,很明顯MainActivity並沒有做其他與界面無關的事情。
優點
降低耦合度,實現了Model和View真正的完全分離。 模塊職責劃分明顯,層次清晰。 Presenter可以復用,一個Presenter可以用於多個View,而不需要更改Presenter的邏輯(當然是在View的改動不影響業務邏輯的前提下)。 如果我們把邏輯放在Presenter中,那麼我們就可以脫離用戶接口來測試這些邏輯(單元測試)。缺點
額外的代碼復雜度及學習成本。 如果Presenter過多地與特定的視圖的聯系過於緊密,一旦視圖需要變更,那麼Presenter也需要變更了。好了,MVP的例子就講到這,其實還有很多種方式來實現MVP,在這裡我也只是講了一個最基礎的方式,但是萬變不離其中。簡要總結MVP三者之間的關系是:View和Model之間沒有聯系,View通過接口與Presenter進行交互,Model不主動和Presenter聯系,被動的等著Presenter來調用其接口,Presenter通過接口和View/Model來聯系。
github源碼下載
RxAndroid之app的生命周期管理RxLifecycle
管理Activity(Fragment、dialogFragment)的生命周期需要在build.gradle中加入compile 'com.trello:rxl
android實現雙日期選擇控件(可隱藏日,只顯示年月)
在安卓開發中,會碰到選開始日期和結束日期的問題。特別是在使用Pad時,如果彈出一個Dialog,能夠同時選擇開始日期和結束日期,那將是極好的。我在開發中在DatePick
AndroidStudio如何快速制作.so
之前寫過一篇Eclipse制作.so的文章,使用的是GNUstep模擬Linux環境,過程現在看來是想相當麻煩,後來發現一個簡單的方法就是通過項目右鍵添加Native S
Android N Preview 行為變更 (版本的 更改)
行為變更Android N 除了提供諸多新特性和功能外,還對系統和 API 行為做出了各種變更。本文重點介紹您應該了解並在開發應用時加以考慮的一些重要變更。如果您之前發布