Android MVP 设计模式

来源:互联网 发布:linux修改用户组 编辑:程序博客网 时间:2024/05/29 12:46

这篇文章参照Hongyang的博客整理。
浅谈 MVP in Android

MVP设计模式

何为MVP

1.View 对应于Activity,负责View的绘制以及与用户交互

2.Model 依然是业务逻辑和实体模型

3.Presenter 负责完成View于Model间的交互

Presenter 在这里类似于一个主持人的角色,他负责Model实体类与VIEW表示层的交互,这个交互通常使用接口实现

MVP的特征

  • Presenter是整个MVP体系的控制中心,而不是单纯的处理View请求的人;

  • View仅仅是用户交互请求的汇报者,对于响应用户交互相关的逻辑和流程,View不参与决策,真正的决策者是Presenter;

  • View向Presenter发送用户交互请求应该采用这样的口吻:“我现在将用户交互请求发送给你,你看着办,需要我的时候我会协助你”,不应该是这样:“我现在处理用户交互请求了,我知道该怎么办,但是我需要你的支持,因为实现业务逻辑的Model只信任你”;

  • 对于绑定到View上的数据,不应该是View从Presenter上“拉”回来的,应该是Presenter主动“推”给View的;

  • View尽可能不维护数据状态,因为其本身仅仅实现单纯的、独立的UI操作;Presenter才是整个体系的协调者,它根据处理用于交互的逻辑给View和Model安排工作。

这里写图片描述
转变成
这里写图片描述

MVC设计模式

1. View:对应于布局文件

2. Model:业务逻辑和实体模型

3. Controllor:对应于Activity

MVC与MVP的不同

MVP与MVC最大的不同是Model不能和VIEW直接通信,必须经过Persenter(主持者)
这里写图片描述

MVP 示例演示

这是模拟登陆的一个demo,使用接口实现MVP设置,在这个demo中,主Activity并没有直接调用Login的业务逻辑(Login的业务逻辑应写在user-Model中),而是使用Persenter通过接口实现login流程,通过接口实现可以进一步解耦。
这里写图片描述

代码结构

这里写图片描述

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.mvp_pattern.MainActivity" >    <EditText        android:id="@+id/id_et_username"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <EditText        android:id="@+id/id_et_pwd"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/id_btn_submit"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="Login" />    <ProgressBar        android:id="@+id/id_pb_loading"        style="@android:style/Widget.ProgressBar.Inverse"        android:layout_width="50dp"        android:layout_height="50dp"        android:visibility="gone" /></LinearLayout>

下面是Model层

User类

public class User {    private String username;    private String password;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }}

User模型的登录流程写在BIZ 包中,也属于MODEL

public interface IUserBIZ {    void login(String username, String password, OnLoginListener listener);}
public interface OnLoginListener {    void loginSuccess(User user);    void loginFail();}

登录流程

public class UserBIZ implements IUserBIZ {    @Override    public void login(final String username, final String password,            final OnLoginListener listener) {        // 使用子线程模拟耗时操作        new Thread() {            @Override            public void run() {                try {                    sleep(2000);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                // 判断是否登录成功                if (username.equals("ytr") && password.equals("123")) {                    User user = new User();                    user.setUsername(username);                    user.setPassword(password);                    if (listener != null) {                        listener.loginSuccess(user);                    }                } else {                    if (listener != null) {                        listener.loginFail();                    }                }            };        }.start();    }}

VIEW层,用于描述界面,需用接口进行约束,只后用于和Presenter交互

// 登录界面需实现的接口public interface IUserLoginView {    String getUserName();    String getPassword();    void clearUserName();    void clearPassword();    void showLoading();    void hideLoading();    void toMainActivity();    void showFailError();}

Persenter 交互核心,通过接口实现Model和View的交互

// presenter角色,是Model和View交互的桥梁public class LoginPresenter {    private IUserBIZ mUserBIZ;    private IUserLoginView mLoginView;    // 用于在UI线程中更新UI    private Handler mHandler = new Handler();    public LoginPresenter(IUserLoginView loginView) {        mLoginView = loginView;        mUserBIZ = new UserBIZ();    }    public void login() {        mLoginView.showLoading();        mUserBIZ.login(mLoginView.getUserName(), mLoginView.getPassword(),                new OnLoginListener() {                    @Override                    public void loginSuccess(User user) {                        // 在UI线程更新UI                        mHandler.post(new Runnable() {                            @Override                            public void run() {                                mLoginView.toMainActivity(); // 登录操作                                mLoginView.hideLoading();                            }                        });                    }                    @Override                    public void loginFail() {                        mHandler.post(new Runnable() {                            @Override                            public void run() {                                mLoginView.showFailError(); // 登录操作                                mLoginView.hideLoading();                            }                        });                    }                });    }    public void clear() {        mLoginView.clearPassword();        mLoginView.clearUserName();    }}

Activity和LoginPresenter交互 M–V–P交互的实现

public class MainActivity extends ActionBarActivity implements IUserLoginView {    private EditText mEtUser;    private EditText mEtPwd;    private Button mBtnLogin;    private ProgressBar mPbLoading;    private LoginPresenter mPresenter = new LoginPresenter(this);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mEtUser = (EditText) findViewById(R.id.id_et_username);        mEtPwd = (EditText) findViewById(R.id.id_et_pwd);        mBtnLogin = (Button) findViewById(R.id.id_btn_submit);        mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading);        mBtnLogin.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View arg0) {                // 登录操作                mPresenter.login();            }        });    }    @Override    public String getUserName() {        return mEtUser.getText().toString();    }    @Override    public String getPassword() {        return mEtPwd.getText().toString();    }    @Override    public void clearUserName() {        mEtUser.setText("");    }    @Override    public void clearPassword() {        mEtPwd.setText("");    }    @Override    public void showLoading() {        mPbLoading.setVisibility(View.VISIBLE);    }    @Override    public void hideLoading() {        mPbLoading.setVisibility(View.GONE);    }    @Override    public void toMainActivity() {        Toast.makeText(this, "toMainActivity()", Toast.LENGTH_SHORT).show();    }    @Override    public void showFailError() {        Toast.makeText(this, "LoginFail", Toast.LENGTH_SHORT).show();    }}
0 0