Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android架構(一)MVP全解析

Android架構(一)MVP全解析

編輯:關於Android編程

前言

關於架構的文章,博主很早就想寫了,雖說最近比較流行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 = 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來獲取數據,同時在回調函數中調用自己定義的回調函數。

實現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 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源碼下載

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved