浅谈Android中的MVP模式

MVP这种设计模式在Android领域越来越火,经常会听到某某Android应用采用了MVP+Retrofit+RxJava的架构,甚至很多工程师都说面试过的人喜欢提MVP,却并不知道它真正的机制。那么,究竟什么是MVP模式,它又与MVC模式有什么异同呢?


MVP与MVC

相信对于大部分开发者而言,MVC是一种非常熟悉的模式,它广泛的应用于web等诸多常见的软件中。MVC将整个工程分为三个部分,Model(模型)、View(视图)、Controller(控制器)中,对于以往常用的Android项目而言,更多的人们会将布局文件作为View,而将Activity(或Fragment,下同)作为Controller。

然而,在Activity中实际上做了很多的事情,不仅处理了业务逻辑,有时也会对UI进行操作,这样就使得Activity看起来既像Controller层又像View层,随着项目的不断发展,这些Activity和Fragment就会变得越来越臃肿,难以扩展和维护,因此便出现了MVP模式。

作为MVC的演化版本,在MVP模式中,将整个工程分为了Model(模型)、View(视图)、Presenter(表示器),与MVC的异同见下图(来自图片):


在图中我们能够看出,MVP与MVC最大的不同就是在于Model与View并不能直接交互,而是隔着一层Presenter,相比于MVC,MVP中的Model会更少的关注业务逻辑,与View的耦合度也进一步降低,这种模式不仅使得代码逻辑更加清晰,同时也能减少我们部署以及单元测试的时间。


Demo

网上很多例子都是使用的用户登录(当然也有很多比较复杂的),所以实现了一个其他的功能,主要用于说明各模块之间的关系。

demo实现的效果如下图,主要功能为输入一个字符串,点击按钮将它变成大写并且输出


在这个demo中的java代码结构如下图:


  • Activity用于展示内容
  • biz是业务逻辑层,用于避免在Model中进行逻辑处理
  • model是模型层
  • presenter是表示器层,用于处理Model和View之间的交互
  • view中封装了一些接口,和activity共同组成了视图层

(1)Model层

在Model层中,我们定义了一个Model,名为MyModel

package com.example.steveyg.androiddemo.model;

/**
 * Created by steveyg on 2016/12/20.
 */

public class MyModel {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}
一般很少有实体只包含一个属性,不过此处用于举例就写了一个简单的实体类。接着定义了相应的biz

package com.example.steveyg.androiddemo.biz;

/**
 * Created by steveyg on 2016/12/20.
 */

public interface IMyBiz {
    public void exec(String str, OnExecListener listener);
}
package com.example.steveyg.androiddemo.biz;

import com.example.steveyg.androiddemo.model.MyModel;

/**
 * Created by steveyg on 2016/12/20.
 */

public interface OnExecListener {
    void execSuccess(MyModel model);
}

package com.example.steveyg.androiddemo.biz;

import com.example.steveyg.androiddemo.model.MyModel;

/**
 * Created by steveyg on 2016/12/20.
 */

public class MyBiz implements IMyBiz {
    @Override
    public void exec(final String str, final OnExecListener listener) {
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                MyModel model = new MyModel();
                String result = str.toUpperCase();
                model.setStr(result);
                listener.execSuccess(model);

            }
        }.run();
    }
}

在实现IMyBiz接口的时候,采用了异步的操作,因为大部分需要处理数据的时候都是要和数据库或服务器交互的。

(2)View层

在View层中,首先定义了一个布局文件,里面有一个提示语,一个输入框和一个按钮:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.steveyg.androiddemo.activity.MainActivity">

    <TextView
        android:layout_alignTop="@+id/edit"
        android:layout_alignBottom="@+id/edit"
        android:gravity="center"
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:text="TEXT : " />

    <EditText
        android:id="@+id/edit"
        android:layout_marginRight="10dp"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/submit"
        android:text="submit"
        android:layout_marginTop="10dp"
        android:layout_below="@+id/edit"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>
接着,我们定义一个接口IMyView,里面定义了视图层需要进行的操作:

package com.example.steveyg.androiddemo.view;

import com.example.steveyg.androiddemo.model.MyModel;

/**
 * Created by steveyg on 2016/12/20.
 */

public interface IMyView {
    public String getStr();

    public void showSuccess(MyModel model);
}
getStr()用来获取输入框中的文字,showSuccess()用于展示最后的结果。接着,在Activity中实现相应的方法

package com.example.steveyg.androiddemo.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.example.steveyg.androiddemo.R;
import com.example.steveyg.androiddemo.model.MyModel;
import com.example.steveyg.androiddemo.presenter.MyPresenter;
import com.example.steveyg.androiddemo.view.IMyView;

public class MainActivity extends AppCompatActivity implements IMyView {

    private EditText mEditText;
    private Button mButton;
    private MyPresenter mPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    @Override
    public String getStr() {
        return mEditText.getText().toString();
    }

    @Override
    public void showSuccess(MyModel model) {
        Toast.makeText(this,model.getStr(),Toast.LENGTH_SHORT).show();
    }

    private void init(){
        mPresenter = new MyPresenter(this);
        mEditText = (EditText)findViewById(R.id.edit);
        mButton = (Button)findViewById(R.id.submit);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.exec();
            }
        });
    }
}
(3)Presenter层
Presenter层主要是让View和Model进行交互,因此我们定义一个执行相应功能的方法:

package com.example.steveyg.androiddemo.presenter;

import android.os.Handler;

import com.example.steveyg.androiddemo.biz.IMyBiz;
import com.example.steveyg.androiddemo.biz.MyBiz;
import com.example.steveyg.androiddemo.biz.OnExecListener;
import com.example.steveyg.androiddemo.model.MyModel;
import com.example.steveyg.androiddemo.view.IMyView;


/**
 * Created by steveyg on 2016/12/20.
 */

public class MyPresenter {
    private IMyBiz myBiz;
    private IMyView myView;
    private Handler mHandler = new Handler();

    public MyPresenter( IMyView view) {
        this.myBiz = new MyBiz();
        this.myView = view;
    }

    public void exec() {
        myBiz.exec(myView.getStr(), new OnExecListener() {
            @Override
            public void execSuccess(final MyModel model) {
                //通过Handler在UI线程中处理
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        myView.showSuccess(model);
                    }
                });

            }
        });
    }
}

至此,一个简单的MVP demo就完成啦,不难看出,相比于MVC模式,代码量增加了很多,但是逻辑更加清晰,在实际的项目中,还是要好好设计下整个项目的结构,而且选定一种模式最好能够坚持的使用下去,在中途切换模式,有可能会导致整个项目的重构。


参考资料

http://blog.csdn.net/lmj623565791/article/details/46596109

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0227/2503.html

http://www.cnblogs.com/liuling/archive/2015/12/23/mvp-pattern-android.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值