Android架構(一)MVP全解析

來源:互聯網
上載者:User

標籤:

前言

關於架構的文章,博主很早就想寫了,雖說最近比較流行MVVM,但是MVP以及MVC也沒有過時之說,最主要還是要根據業務來選擇合適的架構。當然現在寫MVP的文章很多,也有很多好的文章,但是大多數看完後還是一頭霧水,用最少的文字表述清楚是我一貫的風格(這裡小小的裝逼一下),所以還是自己總結比較靠譜。

1.回顧MVC

講到MVP前我們有必要回顧下MVC,MVC(Model-View-Controller,模型-視圖-控制器)模式是80年代Smalltalk-80出現的一種軟體設計模式,後來得到了廣泛的應用,用一種商務邏輯、資料、介面顯示分離的方法組織代碼,在改進和個人化定製介面及使用者互動的同時,不需要重新編寫商務邏輯。

android的MVC

Android中介面部分也可以採用了MVC架構,MVC的角色定義分別為:

  • 模型層(Model)
    我們針對業務模型,建立的資料結構和相關的類,就可以理解為Model,Model是與View無關,而與業務相關的。

  • 視圖層(View)
    一般採用xml檔案或者java代碼進行介面的描述,也可以使用javascript+html等的方式作為view層。

  • 控制層(controller)
    android的控制層通常在acitvity、Fragment或者由它們控制的其他業務類中。

android的MVC缺點

在Android開發中,Activity並不是一個標準的MVC模式中的Controller,它的首要職責是載入應用的布局和初始化使用者介面,並接受並處理來自使用者的操作請求,進而作出響應。隨著介面及其邏輯的複雜度不斷提升,Activity類的職責不斷增加,以致變得龐大臃腫。

2.什麼是MVP

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很大的不同之處。

3.使用MVP

這裡我們舉個例子,通過網路擷取文章的標題和內容並顯示在介面上,訪問網路的內容和Android網路編程(三)Volley用法全解析這篇文章所採用的資料是一樣的,Json資料格式請點擊這裡。

訪問網路資料用的是OkHttpFinal,包目錄如所示:

實現Model

首先我們要建立bean檔案,這裡帖上部分代碼:

public class ArticleInfo {    private String desc;    private String status;    private List<detail> detail = new ArrayList<detail>();    public List<ArticleInfo.detail> getDetail() {        return detail;    }    public void setDetail(List<ArticleInfo.detail> 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<ArticleInfo>(){            @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來擷取資料,同時在回呼函數中調用自己定義的回呼函數。

實現Presenter

首先定義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層的實現:

實現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<ArticleInfo.detail> 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並沒有做其他與介面無關的事情。

4.MVP的優缺點

優點

  • 降低耦合度,實現了Model和View真正的完全分離。
  • 模組職責劃分明顯,層次清晰。
  • Presenter可以複用,一個Presenter可以用於多個View,而不需要更改Presenter的邏輯(當然是在View的改動不影響商務邏輯的前提下)。
  • 如果我們把邏輯放在Presenter中,那麼我們就可以脫離使用者介面來測試這些邏輯(單元測試)。

缺點

  • 額外的代碼複雜度及學習成本。
  • 如果Presenter過多地與特定的視圖的聯絡過於緊密,一旦視圖需要變更,那麼Presenter也需要變更了。
5.總結

好了,MVP的例子就講到這,其實還有很多種方式來實現MVP,在這裡我也只是講了一個最基礎的方式,但是萬變不離其中。簡要總結MVP三者之間的關係是:View和Model之間沒有聯絡,View通過介面與Presenter進行互動,Model不主動和Presenter聯絡,被動的等著Presenter來調用其介面,Presenter通過介面和View/Model來聯絡。

github源碼下載

參考資料:
Android中的MVP
Android App的設計架構:MVC,MVP,MVVM與架構經驗談
Android開發中的MVP架構詳解
淺談 MVP in Android
使用MVP模式重構代碼
MVP模式是你的救命稻草嗎?
Android MVP 詳解(上)
MVP模式的優缺點
Android MVP 執行個體運用

Android架構(一)MVP全解析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.