MVP模式

簡介

  • MVP 是從經(jīng)典的模式MVC演變而來。
  • 在MVC/MVP模式中Controller/Presenter負責邏輯的處理,Model提供數(shù)據(jù),View負責顯示。
  • 但是MVP與MVC有著一個重大的區(qū)別:在MVP中View并不直接使用Model,它們之間的通信是通過Presenter (MVC中的Controller)來進行的,所有的交互都發(fā)生在Presenter內(nèi)部,而在MVC中View會直接從Model中讀取數(shù)據(jù)而不是通過 Controller。
    MVC模式中三者的關(guān)系:


    MVC模式.png

    MVP模式中三者的關(guān)系:


    MVP模式.png
  • 事實上,android中的activity就是用到了MVC模式。其中的View對應(yīng)Activity中與XML文件對應(yīng)的View控件部分,而Model則對應(yīng)數(shù)據(jù)庫文件,Sharedprefrence,內(nèi)存緩沖,磁盤緩沖等數(shù)據(jù)內(nèi)容。至于Controller控制層基本上也由Activity層面來進行。
  • 從上面可以看出,在android中,activity同時充當了V和C的角色,使得activity的代碼往往會過于臃腫,也不符合“單一職責”的原則,所以MVP模式就出現(xiàn)了。
  • MVP模式出現(xiàn)后Activity就可以只充當V的角色,M對V或者V對M來說幾乎是完全透明的,提高了系統(tǒng)的可維護性和擴展性。

實例

  • 接下來通過一個登陸界面來運用MVP模式。
  • ILoginModel即Model的接口:
public interface ILoginModel {

    boolean doLogin(String name,String passwrod);

}

其實就是實現(xiàn)一個向遠端服務(wù)器驗證的功能。

  • LoginModel即ILoginModel的實現(xiàn)類:
public class LoginModel implements ILoginModel{


    @Override
    public boolean doLogin(final String name, final String passwrod) {
        boolean result = false;
        try {
            Thread.sleep(3000);
            result = name.equals(passwrod);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }
}

線程睡眠3秒,模擬后臺驗證的過程。

  • LoginContract封裝了View和Presenter的接口:
public interface LoginContract {

    interface LoginView {

        void setPresenter();

        void showLoading();

        void hideLoading();

        void onSuccess();

        void onFail();
    }

    interface LoginPresenter{

        void login(String account, String password);
    }

}

即View需要用的功能是展示加載條,取消加載條,登陸成功的頁面顯示,登陸失敗的頁面顯示。而Presenter暴露給View的方法則是點擊按鈕后需要調(diào)用的login方法。

  • LoginPresenter即Presenter類,View和Model交接的中轉(zhuǎn)站,負責邏輯的處理。
public class LoginPresenter implements LoginContract.LoginPresenter {

    LoginContract.LoginView mView;
    ILoginModel mModel;

    public LoginPresenter(LoginContract.LoginView mView) {
        this.mView = mView;
        this.mModel = new LoginModel();
    }

    @Override
    public void login(final String account, final String password) {
        mView.showLoading();
        new Thread(new Runnable() {
            @Override
            public void run() {
                final boolean result = mModel.doLogin(account,password);
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (result) {
                            mView.hideLoading();
                            mView.onSuccess();
                        }else {
                            mView.hideLoading();
                            mView.onFail();
                        }
                    }
                });
            }
        }).start();

    }
}

login方法中首先調(diào)用View的showLoading()展示加載框,然后新開線程做耗時操作,并通過回調(diào)執(zhí)行對View的其他控制。

  • LoginActivity即View層,負責界面的展示。
public class LoginActivity extends AppCompatActivity implements LoginContract.LoginView{

    private Button mBtLogin;
    private EditText mEtName;
    private EditText mEtPassword;
    private View mLoading;
    LoginContract.LoginPresenter mPresenter;

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

    private void initView() {
        mEtName = (EditText) findViewById(R.id.et_name);
        mEtPassword = (EditText) findViewById(R.id.et_password);
        mBtLogin = (Button) findViewById(R.id.bt_login);
        mLoading = findViewById(R.id.layout_loading);
        mBtLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = mEtName.getText().toString();
                String password = mEtPassword.getText().toString();
                mPresenter.login(name,password);
            }
        });
    }

    @Override
    public void setPresenter() {
        mPresenter = new LoginPresenter(this);
    }

    @Override
    public void showLoading() {
        mLoading.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        mLoading.setVisibility(View.GONE);
    }

    @Override
    public void onSuccess() {
        Toast.makeText(this,"登陸成功",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onFail() {
        Toast.makeText(this,"登陸失敗",Toast.LENGTH_SHORT).show();
    }
}

Presenter可通過契約類LoginContract 中View接口定義的方法來對View進行操作。

  • 使用MVP模式后,M和V對互相透明,M和V其中一方的改變都不會影響其他的一方。

總結(jié)

  • mvp模式比較適合大型的APP開發(fā),越復(fù)雜它的優(yōu)勢越明顯,但是如果頁面本身很簡單,使用MVP模式就會加大工作量,比如上面的登陸界面,明明一個Activity就可以搞定,卻被分成了多個接口和類。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容