简单聊一聊Android中MVP开发

来源:互联网 发布:金蝶k3数据交换平台 编辑:程序博客网 时间:2024/06/05 23:52

前言

新年新气象,Blin祝大家在新的一年中事业一帆风顺!好了,年是过完了,不知道小伙伴们是否也都已经到了工作岗位,开始新的一年的征程了呢。废话不多说,我们这次主要是以聊一聊为主,简单讲一讲在我们的Android开发中被大家普遍接受的MVP开发,上干货!

简介

对于MVP,全称是Model View Presenter,相比对这东西都有点耳熟能详的感觉有木有,现在很多项目都是用这个开发模式进行公司或个性项目的开发。其实我在第一次了解MVP的时候,感觉就是东西不错,但是烦。那么MVP到底是什么呢?其实也很简单,就是由我们以往一直使用的MVC演化而来,如果你做过公司的大型项目,想必你也无时无刻不在抱怨,一个项目主页面的Activity少则数千行,多则上万行。当然此篇博文更多的是作为一篇日记一样以及本人的一些想法,如果有什么问题的话也请大牛们指正,一起相互学习。

和MVC的区别

这一点的话必须要搞清楚,为什么会有MVP,归根结底就是为了弥补一些MVC的缺点。它们的基本思想肯定是有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。

区别如下图:(引用hongyang大神博文的的图片)
这里写图片描述
个人总结MVP的话其实用一句话来说明就可以了:大型项目,多人开发MVP必定是未来的趋势。如果是单人或者两个人开发的
话,个人觉得你用MVC也是很不错的,毕竟MVP开发成本太高,至少从类上来讲,那多出的类的个数差不多是一倍之差啊。
那说了这么多没用的,我们也来总结一下MVP的优点吧:
1、模型与视图完全分离,我们可以修改视图而不影响模型
2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部
3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型
的变化频繁。
4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

Login MVP Demo

还有其他的一些概念性的东西也就不多说了,我们直接看Demo然后来真正的熟悉一下到底MVP开发模式是如何应用在实际的项
目中的,我这里以一个简单的一个登陆系统为例子来说一下吧。(本来想用自己个人项目的【比比账号通】的登录接口,但是为了
简单化,主要是了解MVP,所以我们就模拟一下吧)
首先来看一下我们要实现的效果:
这里写图片描述
这个功能如果大家用MVC来写,那肯定是分分钟的事情,但是如果是用MVP,可能就像我第一次自己写的的时候还真有点不好
写,下图是小项目的结构:
这里写图片描述
那么我们怎么来运用MVP呢,顺着我自己的思路一步一步来,首先既然是一个登陆系统,那么必然存在用户这个bean类,我们先
把bean类写好,如下:
package com.yiguo.blin.loginmvpdemo.bean;

/** * Created by zhaocheng on 2016/2/18. */public class User {    private String telephone;    private String password;    public String getTelephone() {        return telephone;    }    public void setTelephone(String telephone) {        this.telephone = telephone;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }}

(一)Modle

最简单的Bean写好,那么我们就要开始摸索这个MVP中的Modlel.
这个小项目就一个小功能,那就是登陆,那么是谁来用这个功能呢,很显然,不用多讲,新建IUser。如下:

package com.yiguo.blin.loginmvpdemo.model;/** * Created by zhaocheng on 2016/2/18. */public interface IUser {    void login(String telephone,String password,OnLoginListener loginListener);}

当然我这是直接写完后再把代码贴上来,给大家理一遍的,登录功能嘛,肯定要账号密码的,那么为什么还要一个借口呢,也很简
单,就是为了处理登录后,回调接口,用来处理登录后要处理的事情,对吧。应该不难理解的。
然后创建UserModel,去实现上面的接口,代码如下:

package com.yiguo.blin.loginmvpdemo.model;import com.yiguo.blin.loginmvpdemo.bean.User;/** * Created by zhaocheng on 2016/2/22. */public class UserModel implements IUser {    @Override    public void login(final String telephone, final String password, final OnLoginListener loginListener) {        //这边我们需要模拟一个耗时操作        new Thread()        {            @Override            public void run()            {                try                {                    Thread.sleep(1000);                } catch (InterruptedException e)                {                    e.printStackTrace();                }                //然后这边模拟登录成功                if ("blin".equals(telephone) && "000000".equals(password)){                    User user = new User();                    user.setTelephone(telephone);                    user.setPassword(password);                    loginListener.loginSuccess(user);                }else{                    loginListener.loginFailed();                }            }        }.start();    }}

上面的就是主要的Model了,我这边就是模拟了一下登录请求,用子线程睡眠模拟。不要吐槽,我们的重点不是在这里(。・∀・)ノ゙。
然后忘记了一个,上面的接口我们还没有定义呢,当然实际开发你肯定会先写这个回调接口的,不然看上IUser报错也是不爽,尤其是我这种有强迫症的人。

package com.yiguo.blin.loginmvpdemo.model;import com.yiguo.blin.loginmvpdemo.bean.User;/** * Created by zhaocheng on 2016/2/18. */public interface OnLoginListener {    void loginFailed();    void loginSuccess(User user);}

Model其实就是这么简单的,和以往的写法也没什么区别是吧。

(二)View

接下来我们来看看View,其实呢没说白了,我们做这么多就是为了解耦,那么和View相关的事件有什么呢,以往可能直接在
Activity中写的和View有关的事件在MVP中都会通过接口,然后Activity再去实现。所以,刚开始不能理解,或者摸不着头脑的,
可以先按照以往的写法,然后再进去解耦。当然这样的方法肯定是违背了我们用MVP的初衷的。
我也就直接贴出干活了,大家自己看下也应该明白,就是把一些以往直接写在Activity中的和View有关的操作通过接口一一分开封装起来啦。
package com.yiguo.blin.loginmvpdemo.view;

import com.yiguo.blin.loginmvpdemo.bean.User;

/** * Created by zhaocheng on 2016/2/22. */public interface IUserLogin {    String getTelephone();    String getPassword();    void showLoading();    void hideLoading();    void toLoginFailedView();    void toLoginSuccessView(User user);}

然后就是用Activity去实现啊这些方法了呗。

package com.yiguo.blin.loginmvpdemo.view;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import com.yiguo.blin.loginmvpdemo.R;import com.yiguo.blin.loginmvpdemo.bean.User;import com.yiguo.blin.loginmvpdemo.presenter.UserLoginPresenter;public class MainActivity extends AppCompatActivity implements IUserLogin{    private Button btn_login;    private EditText et_account,et_password;    private UserLoginPresenter userLoginPresenter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        init();        initEvent();    }    private void init(){        btn_login = (Button) findViewById(R.id.btn_login);        et_account = (EditText) findViewById(R.id.et_account);        et_password = (EditText) findViewById(R.id.et_password);        userLoginPresenter = new UserLoginPresenter(this);    }    private void initEvent(){        btn_login.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                userLoginPresenter.login();            }        });    }    @Override    public String getTelephone() {        return et_account.getText().toString();    }    @Override    public String getPassword() {        return et_password.getText().toString();    }    @Override    public void showLoading() {        btn_login.setText("正在登陆。。。");    }    @Override    public void hideLoading() {        btn_login.setText("登录");    }    @Override    public void toLoginFailedView() {        Toast.makeText(this,"账号或密码错误!",Toast.LENGTH_SHORT).show();    }    @Override    public void toLoginSuccessView(User user) {        Toast.makeText(this,"欢迎"+user.getTelephone()+"正在跳转。。。",Toast.LENGTH_SHORT).show();    }}

当然我们的Presenter还没写,我就直接把整个Avtivity贴出来了。。。有点不妥。我们从上面的点击事件中可以看到,点击以后就
是通过userLoginPresenter去调用登录方法了。所以真的在Activity中的逻辑你都看不到了,全都的业务都有Presenter接手。

(三)Presenter

最后就是我们的Presenter了,他的出现就是为了帮助我们处理Model和View之间的数据交互啦,基本上所有的业务也都在这里了。

package com.yiguo.blin.loginmvpdemo.presenter;import android.os.Handler;import com.yiguo.blin.loginmvpdemo.bean.User;import com.yiguo.blin.loginmvpdemo.model.OnLoginListener;import com.yiguo.blin.loginmvpdemo.model.UserModel;import com.yiguo.blin.loginmvpdemo.view.IUserLogin;/** * Created by zhaocheng on 2016/2/22. */public class UserLoginPresenter {    private UserModel userModel;    private IUserLogin userView;    public  User user;    private Handler handler = new Handler();    public UserLoginPresenter(IUserLogin userView){        userModel = new UserModel();        this.userView = userView;        this.user = new User();    }    public void login(){        userView.showLoading();        userModel.login(userView.getTelephone().toString(), userView.getPassword().toString(), new OnLoginListener() {            @Override            public void loginFailed() {                //注意这里,我们是模拟了延迟操作,而且是在子线程,所以这里要调用改变UI的操作必须回到主线程。                handler.post(new Runnable() {                    @Override                    public void run() {                        userView.toLoginFailedView();                        userView.hideLoading();                    }                });            }            @Override            public void loginSuccess(final User user) {                //同上                handler.post(new Runnable() {                    @Override                    public void run() {                        userView.toLoginSuccessView(user);                        userView.hideLoading();                    }                });            }        });    }}

业务就是一个登录,对的,那就来一个登录的方法接口呗。用我们最简单的逻辑去想一下,当点击登录以后,然后调用登录方法,
那么在Presenter中肯定有我们在Activity中实现的接口对象,还有就是Model对象。还有就是那个回调接口直接在这里被初始化
传入,然后处理登录后处理相应的操作,就是因为接口对象的存在,才使得Activity中的方法在Presenter中被轻松的调用到。

总的来说,对于刚入门的,可能这几个接口就把你搞晕了,的确是有点绕,比直接使用我们习惯的MVC的确要夺走一点路子。但是这些东西也是值得的,试想,本来一个页面中的东西可能用MVC开发,等到大家都签入的时候,各种冲突,然而如果是用MVP
开发的话,大家同时使用的就那个Activity,就是每个人多了一些业务接口呗。

大家刚接触的绝对不要慌,这个东西其实昨天和我朋友两个人也聊了很多,的确发现很多年以避免的问题,尤其是类爆炸,或者是当业务逻辑比较复杂时,自己都会搞晕,或者说为了写一个简单的功能浪费了2倍的时间等等,但是作为一个Android的 不管以后是不是会成为主流,但是相比还是要了解一下的,对吧。

PS

好啦,这是2016的第一篇,今天又是元宵,祝大家节日快乐哈~

代码下载地址:

Android MVP 下载

0 0