andorid设计模式系列二:andorid中的MVP模式(上)

整理自:http://kaedea.com/2015/10/11/android-mvp-pattern/

前面在设计模式(1):andorid中的MVC模式,我们讲到了MVC模式的问题,所以自然引出了我们今天的主角:MVP模式

MVP优点:

  • 分离了视图逻辑和业务逻辑,降低了耦合
  • Activity 只处理生命周期的任务,代码变得更加简洁
  • 视图逻辑和业务逻辑分别抽象到了 View 和 Presenter 的接口中去,提高代码的可阅读性
  • Presenter 被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
  • 把业务逻辑抽到 Presenter 中去,避免后台线程引用着 Activity 导致 Activity 的资源无法被系统回收从而引起内存泄露和 OOM

其中说的方便单元测试指的就是:

一般单元测试都是用来测试某些新加的业务逻辑有没有问题,如果采用传统的代码风格(习惯性上叫做 MV 模式,少了 P),我们可能要先在 Activity 里写一段测试代码,测试完了再把测试代码删掉换成正式代码,这时如果发现业务有问题又得换回测试代码,咦,测试代码已经删掉了!好吧重新写吧……
MVP 中,由于业务逻辑都在 Presenter 里,我们完全可以写一个 PresenterTest 的实现类继承 Presenter 的接口,现在只要在 Activity 里把 Presenter 的创建换成 PresenterTest,就能进行单元测试了,测试完再换回来即可。万一发现还得进行测试,那就再换成 PresenterTest 吧。


MVP 的主要特点就是把 Activity 里的许多逻辑都抽离到 View 和 Presenter 接口中去,并由具体的实现类来完成。这种写法多了许多 IView 和 IPresenter 的接口,在某种程度上加大了开发的工作量,刚开始使用 MVP 的小伙伴可能会觉得这种写法比较别扭,而且难以记住。其实一开始想太多也没有什么卵用,只要在具体项目中多写几次,就能熟悉 MVP 模式的写法,理解 TA 的意图,以及享♂受其带来的好处。


MVP使用实例:

这里写图片描述

一个简单的登录界面(实在想不到别的了╮( ̄▽ ̄”)╭),点击 LOGIN 则进行账号密码验证,点击 CLEAR 则重置输入。

这里写图片描述

首先来看看 LoginActivity:

public class LoginActivity extends ActionBarActivity implements ILoginView, View.OnClickListener {
    private EditText editUser;
    private EditText editPass;
    private Button   btnLogin;
    private Button   btnClear;
    ILoginPresenter loginPresenter;
    private ProgressBar progressBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //find view
        editUser = (EditText) this.findViewById(R.id.et_login_username);
        editPass = (EditText) this.findViewById(R.id.et_login_password);
        btnLogin = (Button) this.findViewById(R.id.btn_login_login);
        btnClear = (Button) this.findViewById(R.id.btn_login_clear);
        progressBar = (ProgressBar) this.findViewById(R.id.progress_login);
        //set listener
        btnLogin.setOnClickListener(this);
        btnClear.setOnClickListener(this);
        //init
        loginPresenter = new LoginPresenterCompl(this);
        loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_login_clear:
                loginPresenter.clear();
                break;
            case R.id.btn_login_login:
                loginPresenter.setProgressBarVisiblity(View.VISIBLE);
                btnLogin.setEnabled(false);
                btnClear.setEnabled(false);
                loginPresenter.doLogin(editUser.getText().toString(), editPass.getText().toString());
                break;
        }
    }
    @Override
    public void onClearText() {
        editUser.setText("");
        editPass.setText("");
    }
    @Override
    public void onLoginResult(Boolean result, int code) {
        loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
        btnLogin.setEnabled(true);
        btnClear.setEnabled(true);
        if (result){
            Toast.makeText(this,"Login Success",Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, HomeActivity.class));
        }
        else
            Toast.makeText(this,"Login Fail, code = " + code,Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onSetProgressBarVisibility(int visibility) {
        progressBar.setVisibility(visibility);
    }
}

从代码可以看出 LoginActivity 只做了 findView 以及 setListener 的工作,而且包含了一个 ILoginPresenter,所有业务逻辑都是通过调用 ILoginPresenter 的具体接口来完成。所以 LoginActivity 的代码看起来很舒爽,甚至有点愉♂悦呢 (/ω\*)。视力不错的你可能还看到了 ILoginView 接口的实现,如果不懂为什么要这样写的话,可以先往下看,这里只要记住 “LoginActivity 实现了 ILoginView 接口”。

再来看看 ILoginPresenter

public interface ILoginPresenter {
    void clear();
    void doLogin(String name, String passwd);
    void setProgressBarVisiblity(int visiblity);
}
public class LoginPresenterCompl implements ILoginPresenter {
    ILoginView iLoginView;
    IUser user;
    Handler    handler;
    public LoginPresenterCompl(ILoginView iLoginView) {
        this.iLoginView = iLoginView;
        initUser();
        handler = new Handler(Looper.getMainLooper());
    }
    @Override
    public void clear() {
        iLoginView.onClearText();
    }
    @Override
    public void doLogin(String name, String passwd) {
        Boolean isLoginSuccess = true;
        final int code = user.checkUserValidity(name,passwd);
        if (code!=0) isLoginSuccess = false;
        final Boolean result = isLoginSuccess;
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                iLoginView.onLoginResult(result, code);
            }
        }, 3000);
    }
    @Override
    public void setProgressBarVisiblity(int visiblity){
        iLoginView.onSetProgressBarVisibility(visiblity);
    }
    private void initUser(){
        user = new UserModel("mvp","mvp");
    }
}

从代码可以看出,LoginPresenterCompl 保留了 ILoginView 的引用,因此在 LoginPresenterCompl 里就可以直接进行 UI 操作了,而不用在 Activity 里完成。这里使用了 ILoginView 引用,而不是直接使用 Activity,这样一来,如果在别的 Activity 里也需要用到相同的业务逻辑,就可以直接复用 LoginPresenterCompl 类了(一个 Activity 可以包含一个以上的 Presenter,总之,需要什么业务就 new 什么样的 Presenter,是不是很灵活(@ ̄︶ ̄@)),这也是 MVP 的核心思想

再来看看 ILoginView,至于 ILoginView 的实现类呢,翻到上面看看 LoginActivity 吧

public interface ILoginView {
    public void onClearText();
    public void onLoginResult(Boolean result, int code);
    public void onSetProgressBarVisibility(int visibility);
}

上面的内容来自我引用的个人IT站,我自己在这里总结一下:

无一例外,M(Model)V(View)P(Prenster)三者首先都要有一个interface接口,里面写着你根据业务逻辑要求想要实现的抽象方法。然后这些抽象方法最后会在对应的实现类里实现。

  • 先说V(View):
    很显然,Activity是作为View的具体实现类用来处理界面逻辑,LoginActivity继承ILoginView,在ILoginView中我们定义好我们界面逻辑需要的抽象方法,然后在LoginActivity中实现,这个没有太多可说的

  • 再说P(Presenter):
    P处理业务逻辑,一个接口:ILoginPresenter,然后在里面写入我们需要的业务逻辑抽象方法,再创建一个类LoginPresenterCompl ,继承 ILoginPresenter,然后实现这些继承的抽象方法。
    这里有一个小问题,就是业务逻辑处理完之后往往需要对界面作出调整,所以我们需要在LoginPresenterCompl 创建一个ILoginView 引用,然后我们在Activity中创建LoginPresenterCompl 对象的时候把Activity本身当作参数传入(注意这个Activity是继承了ILoginView 的)赋值给这个ILoginView 引用,然后根据多态性,我们就可以直接在LoginPresenterCompl 中对这个ILoginView 进行操作(调用的实际上却是Activity中实现了的ILoginView 方法)。

  • 关于M(Model):
    这个没什么可说的,就不说了

当然以上只是最简单的MVP模式的运用,还有一些我们常用的比如说Adapter的MVP模式使用我们以后再更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值