从零开始学MVP架构 - 由更浅到浅

前言

首先如果你是一个半年以内的安卓初学者,如果你对逻辑思维的感受不够强烈的话,我不建议你立马接触MVP设计模式。为什么呢?因为我自己就是这波人里面的…尴尬个三秒钟,跳过。这种东西具体是什么呢?

身边其实有很多类似的例子,如果非要举个例子,我个人感觉跟盖房子有那么一丢丢类似,但又不完全类似。

以一个大型公司为例,它会分很多的部门,然后每个部门具有一定的职能,但其实很多公司的部门架构都是具有一定的相似性的,这也就是我们通常说的模式化~而每个人做的事情也许别人也能做,就好比Activity里面你也可以做联网操作,也可以做View操作,但是你啥事儿都让他一个做是不是有点累呢?所以,合理的结构与分工可以让整个综合体更有效率的运行与维护。

在此之前,我希望初学者不是抱着一口吃个胖子的心态去接触这种设计模式。由更浅到浅,会让你理解更明白。在学习MVP以前,我强烈建议先学习MVC【标准MVC不是那种不三不四的结构的Demo或者渣渣项目】,把这种分模块与分层的思想带到你的项目中。这里是我的MVC学习笔记:http://www.jianshu.com/p/894420ac8fdc

不懂的哥们姐们多写几遍,一定不要懒~

入门

首先对于网上的那些理论性的玩意儿,我不想复制粘贴过来。一个原因,太抽象不具体。我们很难理解那些看不到的玩意儿。

如果你学会了MVC,那你应该就会有一种体会,就是你的联网操作,数据操作,以及一些耗时的操作等都是写在Model中的,然后你把数据塞到要显示的View中的时候,都是在Activity或Fragment等等这些Java文件中的,那么这么做的好处是啥?没有好处我们肯定不会用它的对吧,我想很多人刚开始学习安卓的时候,写demo,例如写一个显示天气数据的Activity,肯定你View也写在里头,联网也写在里头,然后第一步怎么联网,第二步回调怎么写数据,第三部怎么显示消失动画等等…其实这也没啥,但是你啥都写在一个里面,你一个Activity要写两千多行咩?协同开发的时候是不是给别人一种坑的感觉咩?

同样是写个显示天气数据的demo,使用MVC,你的View相关的操作,全部是在Activity中的,而你的联网等全部是在Model中的,这样的话,我们就吧视图【你眼睛看到的,手摸到的】与联网【比较耗时间的需要异步的】,这两种行为用代码隔开了。对于单个文件来说,降低代码量,易于维护。对于模块式的开发形式来说,独立的东西往往比黏合在一起的东西好控制,也就是我们常说的解耦。

然后,在我学会MVC以后我再写MVP就很容易明白它的目的了。首先MVC我们已经清楚,M是做耗时操作与业务逻辑处理的,View是我们眼睛看到的,你就把它当作布局文件就好不要想太复杂。然后C就是controller,就是我们把布局文件连接起来的,那不就是我们的Activity嘛。然后,MVP则相当于进化版本的MVC。我们知道,如果你要把一行文字塞到TextView中,要使用的是setText的方法,这个方法是针对TextView这个View的操作,而你塞进去,这一动作,我们要把它独立出来看,比如我吃饭,我的吃,与饭进到嘴巴里面,综合来看是一个行为动作,但是这里呢就把它进一步独立开,吃是逻辑,而饭进到嘴巴里才是针对你的嘴巴的操作。

以上逻辑的解释如果你还看不懂,哥哥我就不好说啥了…

代码【demo参照:http://blog.csdn.net/knxw0001/article/details/39637273/ 进行了少量修改】

我们要实现一个这样的功能:可以从EditText读取用户信息并存取,也可以根据ID来从后台读出用户信息并显示在EditText中。

首先来看一下分包

分包

看一下布局:

布局文件

布局文件的相关代码我就不贴上来了比较简单

然后看上面那个分包的图,首先如果你会MVC,你就知道Model的作用是放置耗时的操作与业务逻辑的模块,在这个demo中,Model要做的事情是什么?主要做的工作是,把从View中拿到的数据存起来,以及从存入的地方读出来并且拿出来使用。

UserBean


public class UserBean {

    public UserBean(String first_name, String last_name) {
        this.first_name = first_name;
        this.last_name = last_name;
    }

    private String first_name;

    private String last_name;

    public String getFirst_name() {
        return first_name;
    }

    public void setFirst_name(String first_name) {
        this.first_name = first_name;
    }

    public String getLast_name() {
        return last_name;
    }

    public void setLast_name(String last_name) {
        this.last_name = last_name;
    }
}

看一下UserModel接口以及它的实现类UserModelImp,如果你不知道为啥子要写个实现类,建议你先去把MVC学会并且使用熟练。

UserModel

相关备注:UserModel主要做的工作是,把从View中拿到的数据存起来,以及从存入的地方读出来给别的地方用

public interface UserModel {

    void setId(int id);

    void setFirstName(String first_name);

    void setLastName(String last_name);

    UserBean getUserInfo(int id);//通过id获取first_name与last_name,返回一个UserBean

}

UserModelImp

相关备注:实现UserModel接口,来把具体要做的工作放在这里

public class UserModelImp implements UserModel {

    private int id;
    private String first_name;

    @Override
    public void setId(int id) {
        this.id = id;
    }

    @Override
    public void setFirstName(String first_name) {
        if (first_name != null && first_name.length() > 0) {
            this.first_name = first_name;
        } else {
            Toast.makeText(MainApplication.MainContext, "首次姓名不能为空", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void setLastName(String last_name) {
        if (last_name != null && last_name.length() > 0) {
            MainApplication.userArray.append(id, new UserBean(first_name, last_name));
            Toast.makeText(MainApplication.MainContext, "存入成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(MainApplication.MainContext, "最后姓名不能为空", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public UserBean getUserInfo(int id) {
        return MainApplication.userArray.get(id);
    }
}

那么在这个例子中的MVP的M部分已经完成,然后要看一下P,P是prensneter,意思是表现,展现出来,它很类似于controller,还以吃饭为例。如果controller表示吃饭这个整体动作,那么presenter就是拆分出来的吃,而View就是把饭送到嘴巴里的动作。

然后我们要先把饭送到嘴巴里才能吃对不对?看一下UserView接口。

UserView

相关备注:UserView可以做的工作是,从EditText塞入或读取数据,即与view的交互
PS:对于View而言,它主要是面对View所做的操作,在本例中,对View的操作主要是从从EditText塞入或读取数据,然后与Button之间存在一定的交互

public interface UserView {

    int getId();

    String getFirstName();

    String getLastName();

    void setFirstName(String first_name);

    void setLastName(String last_name);

    void clearText();

}

然后是吃的逻辑,也就是presenter

UserPresenter

相关备注:Presenter主要起到了一个连接器的作用,也就是承载了大量原来在Activity中的操作
PS:以本例子的需求为例,主要要做两方面的操作,一方面是存,一方面是取,那么要在这里把View和Model的作用发挥出来

public class UserPresenter {

    private UserView userView;

    private UserModel userModel;

    /*这里需要把View的实现类传入*/
    public UserPresenter(UserView userView) {
        this.userView = userView;
        this.userModel = new UserModelImp();//这里是实现类
    }

    /*存的操作*/
    public void saveUserInfo(int id, String first_name, String last_name) {
        if (id != 0) {
            userModel.setId(id);
            userModel.setFirstName(first_name);
            userModel.setLastName(last_name);
        } else {
            Toast.makeText(MainApplication.MainContext, "id不能为0或为空", Toast.LENGTH_SHORT).show();
        }
        userView.clearText();
    }

    /*取的操作*/
    public void readUserInfo(int id) {
        try {
            if (id != 0) {
                userView.setFirstName(userModel.getUserInfo(id).getFirst_name());
                userView.setLastName(userModel.getUserInfo(id).getLast_name());
            } else {
                throw new Exception();
            }
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(MainApplication.MainContext, "未查询到此数据", Toast.LENGTH_SHORT).show();
        }
    }

}

以上关于view和presenter的部署已经完成,接下来就要在Activity中来使用了。

MainActivity


public class MainActivity extends AppCompatActivity implements UserView, View.OnClickListener {

    private EditText etUserID;
    private EditText etUserFirstName;
    private EditText etUserLastName;
    private Button btnSave;
    private Button btnRead;

    private UserPresenter userPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        initView();
        userPresenter = new UserPresenter(this);
    }

    private void initView() {
        etUserID = (EditText) findViewById(R.id.etUserID);
        etUserFirstName = (EditText) findViewById(R.id.etUserFirstName);
        etUserLastName = (EditText) findViewById(R.id.etUserLastName);
        btnSave = (Button) findViewById(R.id.btnSave);
        btnRead = (Button) findViewById(R.id.btnRead);
        btnSave.setOnClickListener(this);
        btnRead.setOnClickListener(this);
    }

    @Override//此方法里没有完全隔离【后期修改】
    public int getId() {
        if (etUserID.getText().toString().length() > 0) {
            return Integer.parseInt(etUserID.getText().toString());
        } else {
            return 0;
        }
    }

    @Override
    public String getFirstName() {
        return etUserFirstName.getText().toString();
    }

    @Override
    public String getLastName() {
        return etUserLastName.getText().toString();
    }

    @Override
    public void setFirstName(String first_name) {
        etUserFirstName.setText(first_name);
    }

    @Override
    public void setLastName(String last_name) {
        etUserLastName.setText(last_name);
    }

    @Override
    public void clearText() {
        etUserID.setText("");
        etUserFirstName.setText("");
        etUserLastName.setText("");
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnSave:
                userPresenter.saveUserInfo(getId(), getFirstName(), getLastName());
                break;

            case R.id.btnRead:
                userPresenter.readUserInfo(getId());
                break;
        }
    }
}

程序入口:MainApplication


public class MainApplication extends Application {

    public static SparseArray<UserBean> userArray = new SparseArray<>();

    public static Context MainContext;

    @Override
    public void onCreate() {
        super.onCreate();
        MainContext = this;
    }
}

可以看到,Activity里已经看不到Model的影子了,Model和View之间的交互全部放在了Presenter里面,很好的隔离了耗时操作了联网等与Activity黏性过高的问题,因为这个例子很经典,也很简单,可以比作一个简单化的登陆demo,但是这个例子还有不足的地方。有时候一个Activity里我们可能会做更多复杂的操作与逻辑,这样的情况下我们可能会写多个Presenter与Model,合理分包,合理的放置逻辑,都是为了实现模块化,独立化的开发思想。

演示效果

3.gif

其他

对于开发来说,有几个比较重要的个人过程。一个是基本理论,理论你都不懂怎么能让程序正常的跑起来?第二个就是思维,思维影响效率,比如有人做家务,他会先做饭,做完饭再扫地,扫完地再洗衣服,可能有的人就是饭正在烧的时候,他打开了洗衣机洗衣服,然后同时去扫地。这就是思维方式的差异,我希望通过最浅显易懂的方式,来把复杂的问题解释清楚,当然如果实在无法理解,也许就是个人天生的思维逻辑不够完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值