Android MVP 框架 Demo

Android中的MVP模式,帶實例

字數2049 閱讀9033 評論30 喜歡119html

本博客原地址:http://www.jianshu.com/p/9d40b298eca9
項目github地址:https://github.com/CameloeAnthony/AndroidMVPDemo
最近在利用工做閒暇時間學習各類網絡的開源項目,也在搭建一個android開源框架,但願可以給對知識作一個總結。
這裏利用一個簡單的應用對MVP作一個講解。後面也有不少github源碼,都是特別經典的例子,能夠學習一下。android

(1). MVP模式簡介

相信你們對MVC都是比較熟悉了:M-Model-模型、V-View-視圖、C-Controller-控制器,MVP做爲MVC的演化版本,那麼相似的MVP所對應的意義:M-Model-模型、V-View-視圖、P-Presenter-表示器。 從MVC和MVP二者結合來看,Controlller/Presenter在MVC/MVP中都起着邏輯控制處理的角色,起着控制各業務流程的做用。而 MVP與MVC最不一樣的一點是M與V是不直接關聯的也是就Model與View不存在直接關係,這二者之間間隔着的是Presenter層,其負責調控 View與Model之間的間接交互。在 Android中很重要的一點就是對UI的操做基本上須要異步進行也就是在MainThread中才能操做UI,因此對View與Model的切斷分離是 合理的。此外Presenter與View、Model的交互使用接口定義交互操做能夠進一步達到鬆耦合也能夠經過接口更加方便地進行單元測試。因此也就有了這張圖片(MVP和MVC的對比)git

MVP和MVC的對比github

其實最明顯的區別就是,MVC中是容許Model和View進行交互的,而MVP中很明顯,Model與View之間的交互由Presenter完成。還有一點就是Presenter與View之間的交互是經過接口的(代碼中會體現)。網絡

(2). MVP模式的應用

2.1 model層描述和具體代碼

提供咱們想要展現在view層的數據和具體登錄業務邏輯處理的實現,架構

package com.nsu.edu.androidmvpdemo.login;

/**
 * Created by Anthony on 2016/2/15.
 * Class Note:模擬登錄的操做的接口,實現類爲LoginModelImpl.至關於MVP模式中的Model層
 */
public interface LoginModel {
    void login(String username, String password, OnLoginFinishedListener listener);
}
package com.nsu.edu.androidmvpdemo.login;

import android.os.Handler;
import android.text.TextUtils;
/**
 * Created by Anthony on 2016/2/15.
 * Class Note:延時模擬登錄(2s),若是名字或者密碼爲空則登錄失敗,不然登錄成功
 */
public class LoginModelImpl implements LoginModel {

    @Override
    public void login(final String username, final String password, final OnLoginFinishedListener listener) {

        new Handler().postDelayed(new Runnable() {
            @Override public void run() {
                boolean error = false;
                if (TextUtils.isEmpty(username)){
                    listener.onUsernameError();//model層裏面回調listener
                    error = true;
                }
                if (TextUtils.isEmpty(password)){
                    listener.onPasswordError();
                    error = true;
                }
                if (!error){
                    listener.onSuccess();
                }
            }
        }, 2000);
    }
}

2.2 view層描述和具體代碼

負責顯示數據、提供友好界面跟用戶交互就行。MVP下Activity和Fragment以及View的子類體如今了這一 層,Activity通常也就作加載UI視圖、設置監聽再交由Presenter處理的一些工做,因此也就須要持有相應Presenter的引用。本層所須要作的操做就是在每一次有相應交互的時候,調用presenter的相關方法就行。(好比說,button點擊)app

package com.nsu.edu.androidmvpdemo.login;

/**
 * Created by Anthony on 2016/2/15.
 * Class Note:登錄View的接口,實現類也就是登錄的activity
 */
public interface LoginView {
    void showProgress();

    void hideProgress();

    void setUsernameError();

    void setPasswordError();

    void navigateToHome();
}
package com.nsu.edu.androidmvpdemo.login;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.nsu.edu.androidmvpdemo.R;

/**
 * Created by Anthony on 2016/2/15.
 * Class Note:MVP模式中View層對應一個activity,這裏是登錄的activity
 */
public class LoginActivity extends Activity implements LoginView, View.OnClickListener {

    private ProgressBar progressBar;
    private EditText username;
    private EditText password;
    private LoginPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        progressBar = (ProgressBar) findViewById(R.id.progress);
        username = (EditText) findViewById(R.id.username);
        password = (EditText) findViewById(R.id.password);
        findViewById(R.id.button).setOnClickListener(this);

        presenter = new LoginPresenterImpl(this);
    }

    @Override
    protected void onDestroy() {
        presenter.onDestroy();
        super.onDestroy();
    }

    @Override
    public void showProgress() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideProgress() {
        progressBar.setVisibility(View.GONE);
    }

    @Override
    public void setUsernameError() {
        username.setError(getString(R.string.username_error));
    }

    @Override
    public void setPasswordError() {
        password.setError(getString(R.string.password_error));
    }

    @Override
    public void navigateToHome() {
// TODO       startActivity(new Intent(this, MainActivity.class));
        Toast.makeText(this,"login success",Toast.LENGTH_SHORT).show();
//        finish();
    }

    @Override
    public void onClick(View v) {
        presenter.validateCredentials(username.getText().toString(), password.getText().toString());
    }

}

2.3 presenter層描述和具體代碼

Presenter扮演着view和model的中間層的角色。獲取model層的數據以後構建view層;也能夠收到view層UI上的反饋命令後分發處理邏輯,交給model層作業務操做。它也能夠決定View層的各類操做。框架

package com.nsu.edu.androidmvpdemo.login;

/**
 * Created by Anthony on 2016/2/15.
 * Class Note:登錄的Presenter 的接口,實現類爲LoginPresenterImpl,完成登錄的驗證,以及銷燬當前view
 */
public interface LoginPresenter {
    void validateCredentials(String username, String password);

    void onDestroy();
}
package com.nsu.edu.androidmvpdemo.login;

/**
 * Created by Anthony on 2016/2/15.
 * Class Note:
 * 1 完成presenter的實現。這裏面主要是Model層和View層的交互和操做。
 * 2  presenter裏面還有個OnLoginFinishedListener,
 * 其在Presenter層實現,給Model層回調,更改View層的狀態,
 * 確保 Model層不直接操做View層。若是沒有這一接口在LoginPresenterImpl實現的話,
 * LoginPresenterImpl只 有View和Model的引用那麼Model怎麼把結果告訴View呢?
 */
public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
    private LoginView loginView;
    private LoginModel loginModel;

    public LoginPresenterImpl(LoginView loginView) {
        this.loginView = loginView;
        this.loginModel = new LoginModelImpl();
    }

    @Override
    public void validateCredentials(String username, String password) {
        if (loginView != null) {
            loginView.showProgress();
        }

        loginModel.login(username, password, this);
    }

    @Override
    public void onDestroy() {
        loginView = null;
    }

    @Override
    public void onUsernameError() {
        if (loginView != null) {
            loginView.setUsernameError();
            loginView.hideProgress();
        }
    }

    @Override
    public void onPasswordError() {
        if (loginView != null) {
            loginView.setPasswordError();
            loginView.hideProgress();
        }
    }

    @Override
    public void onSuccess() {
        if (loginView != null) {
            loginView.navigateToHome();
        }
    }
}

2.4 登錄的回調接口

package com.nsu.edu.androidmvpdemo.login;

/**
 * Created by Anthony on 2016/2/15.
 * Class Note:登錄事件監聽
 */
public interface OnLoginFinishedListener {

    void onUsernameError();

    void onPasswordError();

    void onSuccess();
}

demo的代碼流程:(請參考下面的類圖)

1 Activity作了一些UI初始化的東西並須要實例化對應LoginPresenter的引用和實現 LoginView的接口,監聽界面動做
2 登錄按鈕按下後即接收到登錄的事件,在onClick裏接收到即經過LoginPresenter的引用把它交給LoginPresenter處理。LoginPresenter接收到了登錄的邏輯就知道要登錄了
3 而後LoginPresenter顯示進度條而且把邏輯交給咱們的Model去處理,也就是這裏面的LoginModel,(LoginModel的實現類LoginModelImpl),同時會把OnLoginFinishedListener也就是LoginPresenter自身傳遞給咱們的Model(LoginModel)。
4 LoginModel處理完邏輯以後,結果經過OnLoginFinishedListener回調通知LoginPresenter
5 LoginPresenter再把結果返回給view層的Activity,最後activity顯示結果
請參考這張類圖:異步

本項目類圖ide

(3)注意:


3.1 presenter裏面還有個OnLoginFinishedListener,其在Presenter層實現,給Model層回調,更改View層的狀態,確保 Model層不直接操做View層。
3.2 在一個好的架構中,model層可能只是一個領域層和業務邏輯層的入口,若是咱們參考網上比較火的Uncle Bob clean architecture model層多是一個實現業務用例的交互者,在後續的文章中應該會涉及到這方面的問題,目前能力有限。暫時講解到這裏

(4)MVP經典參考資料

請直接參考文章,這裏面有不少的mvp模式的學習資料:

  • android架構合集(請關注github,後續會不斷更新)
  • android mvp github地址(本篇博客正是參考這個項目進行講解的。這個項目也很簡單,分爲login和main兩個模塊,總共十個類,思路很是清晰。學習的朋友能夠直接clone查看源碼。)

    androidmvp 的src代碼分爲login和main兩個模塊

本項目爲了簡單操做,只添加了login模塊


本項目github地址:
https://github.com/CameloeAnthony/AndroidMVPDemo

相關文章
相關標籤/搜索