欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

浅谈Android中的MVP

程序员文章站 2024-03-15 19:28:36
...

MVP简介

现在所做的项目中大部分的功能都同UI混合在一起,导致代码的耦合性比较查,代码逻辑比较混乱,为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。

在MVP模式里通常包含4个要素:

  • View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);
  • View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;
  • Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);
  • Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑;

MVC和MVP区别

浅谈Android中的MVP

  • 用户 Event(事件)会导致 Controller 改变 Model 或 View 或同时改变两者。
  • 只要 Controller 改变了 Model 的数据或属性,所有依赖的 View 都会自动更新。
  • 类似的,只要 Controller 改变了 View ,View 会从潜在的 Model 中获取数据进行更新。

浅谈Android中的MVP

  • Presenter 中同时持有 View 以及 Model 的 Interface 引用,而 View 持有 Presenter 的实例。
  • 当某个 View 需要展示某些数据时,首先会调用 Presenter 的某个接口,然后 Presenter 会调用 Model 请求数据。
  • 当 Model 数据加载成功后会调用 Presenter 的回调方法通知 Presenter 数据加载完毕,最后 Presenter 再调用 View 层接口展示加载后数据。

主要区别

MVC:

  • View 可以与 Model 直接交互;
  • Controller 可以被多个 View 共享;
  • Controller 可以决定显示哪个 View;

MVP:

  • View 不直接与 Model 交互;
  • Presenter 与 View 通过接口来交互,更有利于添加单元测试;
  • 通常 View 与 Presenter 是一对一的,但复杂的 View 可能绑定多个 Presenter 来处理;
  • Presenter 也可以直接进行 View 上的渲染。

示例

(1)登录示例

浅谈Android中的MVP

(1)Bean实体类

public class LoginBean {

    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;
    }
}

(2)Model接口

public interface ILoginModel {

    public void login(String username, String password, OnLoginListener onLoginListener);
}

(3)Model实体类

public class LoginModel implements ILoginModel {

    @Override
    public void login(final String username, final String password, final OnLoginListener onLoginListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if ("dong".equals(username) && "123".equals(password)) {
                    LoginBean bean = new LoginBean();
                    bean.setUsername(username);
                    bean.setPassword(password);
                    onLoginListener.loginSuccess(bean);
                } else {
                    onLoginListener.loginFailed();
                }
            }
        }).start();
    }
}

(4)接口回调处理

public interface OnLoginListener {

    public void loginSuccess(LoginBean bean);

    public void loginFailed();
}

(5)View接口

public interface ILoginView {

    public String getUserName();

    public String getPassWord();

    public void showLoading();

    public void hideLoading();

    public void dealLoadSuccess(LoginBean bean);

    public void dealLoadFailed();

    public void clearUserName();

    public void clearPassWord();
}

(6)Presenter实体类

public class LoginPresenter {

    private ILoginModel loginModel;
    private ILoginView loginView;

    private Activity mMainActivity;

    public LoginPresenter(ILoginView loginView, Activity mActivity) {
        this.loginView = loginView;
        mMainActivity = mActivity;
        loginModel = new LoginModel();
    }

    public void login() {
        loginView.showLoading();

        loginModel.login(loginView.getUserName(), loginView.getPassWord(), new OnLoginListener() {
            //这里还是子线程中
            @Override
            public void loginSuccess(final LoginBean bean) {

                mMainActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        loginView.hideLoading();

                        loginView.dealLoadSuccess(bean);
                    }
                });
            }

            @Override
            public void loginFailed() {

                mMainActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                        loginView.hideLoading();

                        loginView.dealLoadFailed();
                    }
                });
            }
        });
    }

    public void clear() {
        loginView.clearUserName();
        loginView.clearPassWord();
    }
}

(7)View的实体类

public class LoginActivity extends AppCompatActivity implements View.OnClickListener, ILoginView {

    private EditText username, password;

    private ProgressBar progress;

    private LoginPresenter presenter;

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

        username = (EditText) findViewById(R.id.username);
        password = (EditText) findViewById(R.id.password);
        progress = (ProgressBar) findViewById(R.id.progress);

        findViewById(R.id.login).setOnClickListener(this);
        findViewById(R.id.clear).setOnClickListener(this);

        presenter = new LoginPresenter(this, this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.login:
                presenter.login();
                break;
            case R.id.clear:
                presenter.clear();
                break;
        }
    }

    @Override
    public String getUserName() {
        return username.getText().toString();
    }

    @Override
    public String getPassWord() {
        return password.getText().toString();
    }

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

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

    @Override
    public void dealLoadSuccess(LoginBean bean) {
        Toast.makeText(this, bean.getUsername() + " login success", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void dealLoadFailed() {
        Toast.makeText(this, "login failed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void clearUserName() {
        username.setText("");
    }

    @Override
    public void clearPassWord() {
        password.setText("");
    }
}

(2)注册登录示例

(1)Bean实体类

public class PersonBean {

    private String name;
    private String pwd;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

(2)Model接口

public interface IPersonModel {

    public boolean register(String name, String pwd);

    public boolean login(String name, String pwd);
}

(3)Model实体类

public class PersonModel implements IPersonModel {

    private Map<String, String> personMap = new HashMap<>();

    @Override
    public boolean register(String name, String pwd) {
        if (!personMap.containsKey(name)) {
            personMap.put(name, pwd);
            return true;
        }
        return false;
    }

    @Override
    public boolean login(String name, String pwd) {
        return pwd.equals(personMap.get(name));
    }
}

(4)View接口

public interface IPersonView {

    public boolean checkInputInfo();

    public void registerSuccess();

    public void registerFailed();

    public void loginSuccess();

    public void loginFailed();
}

(5)Presenter实体类

public class PersonPresenter {

    private IPersonModel personModel;
    private IPersonView personView;

    public PersonPresenter(IPersonView personView) {
        this.personView = personView;
        personModel = new PersonModel();
    }

    //注册
    public void register(String name, String pwd) {
        boolean isRegister = personModel.register(name, pwd);
        if (isRegister) {
            personView.registerSuccess();
        } else {
            personView.registerFailed();
        }
    }

    //登录
    public void login(String name, String pwd) {
        boolean isLogin = personModel.login(name, pwd);
        if(isLogin){
            personView.loginSuccess();
        }else{
            personView.loginFailed();
        }
    }
}

(6)View的实体类

public class PersonActivity extends AppCompatActivity implements View.OnClickListener, IPersonView {

    private EditText name, pwd;

    private String inputName, inputPwd;

    private PersonPresenter mPresenter;

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

        name = (EditText) findViewById(R.id.username);
        pwd = (EditText) findViewById(R.id.password);

        findViewById(R.id.login).setOnClickListener(this);
        findViewById(R.id.register).setOnClickListener(this);

        mPresenter = new PersonPresenter(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.login:
                if (checkInputInfo()) {
                    mPresenter.login(inputName, inputPwd);
                }
                break;
            case R.id.register:
                if (checkInputInfo()) {
                    mPresenter.register(inputName, inputPwd);
                }
                break;
        }
    }

    @Override
    public boolean checkInputInfo() {
        inputName = name.getText().toString();
        inputPwd = pwd.getText().toString();

        if ("".equals(inputName)) {
            Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show();
            return false;
        }
        if ("".equals(inputPwd)) {
            Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show();
            return false;
        }

        return true;
    }

    @Override
    public void registerSuccess() {
        Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void registerFailed() {
        Toast.makeText(this, "注册失败", Toast.LENGTH_SHORT).show();
    }

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

    @Override
    public void loginFailed() {
        Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();
    }
}

好啦,MVP的简单介绍就到这里了。