MVP

什么是MVP


mvc

这里写图片描述
 模型(Model):负责处理数据的加载或者存储,比如从网络或本地数据库获取数据等
 
 视图(View):负责界面数据的展示,与用户进行交互,主要是xml文件;
 
 控制器(Controller):控制(Controller)可以理解为从用户接收请求, 将模型与视图匹配在一起,共同完成用户的请求。划分控制层的作用也很明显,它清楚地告诉你,它就是一个分发器,选择什么样的模型,选择什么样的视图,可以完成什么样的用户请求。控制层并不做任何的数据处理。例如,用户点击一个连接,控制层接受请求后, 并不处理业务信息,它只把用户的信息传递给模型,告诉模型做什么,选择符合要求的视图返回给用户。因此,一个模型可能对应多个视图,一个视图可能对应多个模型。


mvp

  MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别代表项目中3个不同的模块。

  模型(Model):负责处理数据的加载或者存储,比如从网络或本地数据库获取数据等;

  视图(View):负责界面数据的展示,与用户进行交互,主要是指Fragment ,Activity;

  主持人(Presenter):相当于协调者,是模型与视图之间的桥梁,将模型与视图分离开来。

  如下图所示,View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。
这里写图片描述

  这样分层的好处就是大大减少了Model与View层之间的耦合度。一方面可以使得View层和Model层单独开发与测试,互不依赖。另一方面Model层可以封装复用,可以极大的减少代码量。
  

  • View发生改变,不影响model
  • model发生改变,不影响View
  • presenter发生改变,只需要改persenter

下面看下MVP模式在具体项目(登录)中的使用。

1.model层描述和具体代码

  • 提供我们想要展示在view层的数据和具体登陆业务逻辑处理的实现
package com.delta.ams.mvpdemo.model.login;

import android.content.Context;

public interface LoginModel {
    public void login(String username, String password, Context context);

    public void logout();
}

LoginModelImp

package com.delta.ams.mvpdemo.model.login;

import android.content.Context;
import android.util.Log;

import com.android.volley.AuthFailureError;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.delta.ams.mvpdemo.MyApplication;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

public class LoginModelImpl implements LoginModel {
    private OnLoginListener mOnLoginListener;
    private final static String LOG_TAG = LoginDaoImpl.class.getSimpleName();

    public void setOnLoginListener(OnLoginListener mOnLoginListener) {
        this.mOnLoginListener = mOnLoginListener;
    }
    public void login(String username, String password, final Context context) {
        Map<String, String> param = new HashMap<>();
        param.put("name", username);
        param.put("pwd", password);
        JSONObject object = new JSONObject(param);
        JsonObjectRequest request = new JsonObjectRequest(Method.POST,
                com.delta.ams.mvpdemo.Common.URL.LOGIN_URL, object, new Listener<JSONObject>() {

            @Override
            public void onResponse(JSONObject response) {
                if (mOnLoginListener != null) {
                    if (response != null) {
                        mOnLoginListener.onSuccess(response
                                .toString());
                    }
                }

            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                if (error != null) {

                    mOnLoginListener.onFailed(error.getMessage());
                }
            }
        }) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                return super.getHeaders();
            }
        };
        Log.i(LOG_TAG, "Body" + new String(request.getBody()));
        try {
            Log.i(LOG_TAG, request.getHeaders().toString());
        } catch (AuthFailureError e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        MyApplication.getQueue().add(request);

    }

    @Override
    public void logout() {

    }

    public interface OnLoginListener {
        void onSuccess(String cookies);
        void onFailed(String errorMsg);
    }

}

2.view层描述和具体代码

  • 负责显示数据、提供友好界面跟用户交互就行。MVP下Activity和Fragment以及View的子类体 现在了这一 层,Activity一般也就做加载UI视图、设置监听再交由Presenter处理的一些工作,所以也就需要持有相应Presenter的引用。本层所需要做的操作就是在每一次有相应交互的时候,调用presenter的相关方法就行。(比如说,button点击)
package com.delta.ams.mvpdemo.Base;

/**
 * Created by V.wenju.tian on 2016/8/18.
 */
public interface BaseView {

    void close();

    void showProgress(String msg);

    void showProgress(String msg, int progress);

    void hideProgress();

    void showErrorMessage(String msg, String content);
}
interface LoginView extends BaseView {

        void LoginSucess(String response);

        void LoginError(String errorMessage);
    }
package com.delta.ams.mvpdemo;

import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.delta.ams.mvpdemo.Base.AbsBaseActivity;
import com.delta.ams.mvpdemo.ui.login.login_contact.LoginContract;
import com.delta.ams.mvpdemo.ui.login.login_contact.LoginPersenter;

public class MainActivity extends  implements LoginView, View.OnClickListener {


    private EditText et_name;
    private EditText et_password;
    private Button bt_login;
    private LoginPersenter mLoginPersenter;
    private String mUserName;
    private String mUserPassword;




    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        mLoginPersenter
                = new LoginPersenter();
        mLoginPersenter.attachView(this);
        et_name = (EditText) findViewById(R.id.et_name);
        et_password = (EditText) findViewById(R.id.et_password);
        bt_login = (Button) findViewById(R.id.bt_login);
        bt_login.setOnClickListener(this);
    }



    @Override
    public void LoginSucess(String response) {

        Log.d("dsd", "LoginSucess() called with: " + "response = [" + response + "]");
        Toast.makeText(this, "正常", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void LoginError(String errorMessage) {
        Log.d("dsd", "LoginError: ");
        Toast.makeText(this, "失败", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onClick(View v) {
        mUserName = et_name.getText().toString().trim();
        mUserPassword = et_password.getText().toString().trim();
        mLoginPersenter.login(mUserName, mUserPassword,this);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLoginPersenter.detachView();
    }
}

3.Presenter

  • Presenter扮演着view和model的中间层的角色。获取model层的数据之后构建view层;也可以收到view层UI上的反馈命令后分发处理逻辑,交给model层做业务操作。它也可以决定View层的各种操作。
package com.delta.ams.mvpdemo.Base;

/**
 *
 * Class Note:
 * MVP中所有Presenter的接口,完成view的绑定和解除
 *
 */
public interface BasePresenter<T extends BaseView> {
    /**
     * 注入View,使之能够与View相互响应
     *
     * @param view
     */
    void attachView(T view);

    /**
     * 释放资源
     */
    void detachView();

}
package com.delta.ams.mvpdemo.ui.login.login_contact;

import android.content.Context;
import android.text.TextUtils;
import android.widget.Toast;

import com.delta.ams.mvpdemo.model.login.LoginDaoImpl;

/**
 * Created by V.wenju.tian on 2016/8/18.
 */
public class LoginPersenter implements LoginPersenter {


    private LoginView mView;
    private Context mContext;
    private LoginModelImpl mLoginModel;

    @Override
    public void attachView(LoginView view) {
        this.mView = view;
        mLoginModel = new LoginModelImpl();

    }

    @Override
    public void detachView() {

        mView = null;
    }


    @Override
    public void login(String name, String passWord, Context mcontext) {

        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(passWord)) {

            Toast.makeText(mContext, "sdsdd", Toast.LENGTH_SHORT).show();
        } else {
             mLoginModel.login(name, passWord, mcontext);
             mView.showProgress("登陆中。。");
             mLoginModel.setOnLoginListener(new LoginModelImpl.OnLoginListener() {
                @Override
                public void onSuccess(String cookies) {

                    mView.LoginSucess(cookies);
                    mView.hideProgress();
                }

                @Override
                public void onFailed(String errorMsg) {
                    mView.LoginError(errorMsg);
                    mView.hideProgress();
                }
            });

        }

    }
}

4.类图
这里写图片描述
5.流程

业务流程
    1.Activity做了一些UI初始化的东西并需要实例化对应LoginPresenter的引用和实现 LoginView的接口,登陆按钮按下后即接收到登陆的事件,在onClick里接收到即通过LoginPresenter的引用把它交给LoginPresenter处理。

2. 然后LoginPresenter显示进度条并且把逻辑交给我们的Model去处理,也就是这里面的LoginModel,(LoginModel现类LoginModelImpl)。

3.这时候通过onLoginListener回调传回所要的结果给Pesenter,然后在做相应的处理。 

4. presenter把回调结果通知给mView,从而实现视图的更新。                                           

6.项目地址
https://github.com/tianwenju/MvPCommonDemoTest

AspNetForums 的汉化版和改写版,主要改写在于: 1、修改了邮件发送程序,设计了可发送需要身份验证的邮件发送组件。 2、设计了一个统一用户群组件(OneUsers.dll),只要你使用 OneUsers 的用户群(数据库可以使用我们的也可以使用你们自己的,我们提供 OneUsers 的数据库的 SQL 脚本),用户只要在加入本站用户群的任何一个论坛注册一次,就可以在其他论坛以同样的帐号登陆。 比如,你在 www.chinamvp.org 注册一次,那么你也可以用此帐号在 www.onebbs.net 登陆,而无需再次注册。 安装文档 1、必须安装MS SQL SERVER 2、必须安装.Net Framework + IIS 1、安装 MS SQL SERVER 论坛数据库文件 首先在 查询分析器里执行 aspnetforums_oneuser1.0.sql脚本安装论坛数据库 然后是 CreateDefaultData1.0.sql 安装默认数据 oneuser1.0.sql 是我们统一使用的用户群库,你可以不安装,而是使用我们的默认数据库,这个默认数据库在我们的服务器上。 如果你是英文系统 请执行 aspnetforums_oneuser1.0forEnSqlServer.sql 和 oneuser1.0forEnSqlServer.sql 但是不能保证论坛 能够正常执行 2、设置 AspNetForums 里的web.config <add key="connectionString" value="server=localhost; User ID=sa; Password=;database=aspnetforums" /> aspnetforums数据库 用户名和密码 <add key="connectionString" value="server=localhost; User ID=sa;database=OneUser" /> oneuser数据库 用户名和密码,你可以删除他或者注释掉,那么就是默认使用我们服务器上的统一用户库 3、设置邮件服务器 <add key="smtpServer" value="yourhost.com" /> <!-- Can specify SMTP Server to use to send out emails. Use "default" to use the default Windows 2000 SMTP Server --> <add key="ChinaASPXMailer" value="True" /> <!-- 如果你使用我们定制的邮件发送组件,请设为 True --> <add key="UserName" value="test@yourhost.com" /> <!--ChinaASPXMailer s UserName ,For Auth mail server --> <add key="Password" value="test" /> <!--ChinaASPXMailer s Password ,For Auth mail server --> <add key="Port" value="25" /> <!-- Port for ChinaASPXMailer s prot --> <add key="FromName" value="ChinaMVP.COM" /> <!-- FromName for ChinaASPXMailer s FromName --> <!--add key="Charset" value="GB2312" /--> <!-- FromName for ChinaASPXMailer s FromName ,Default value is gb2312 --> 把以上的 yourhost.com 改成你的邮件服务器 如果需要验证,请设置 UserName,否则 删除或者注释掉 4 、设置IIS,在你的web站点里设置一个虚拟目录 其物理目录指向 AspNetForums 目录。 5、解决方案 EngineAspNetForums.sln 6、管理员帐号: user:admin pwd:admin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值