关于MVP

总体来说MVP就是通过一大堆接口回调拆分理清业务逻辑,从逻辑思维上达到简化代码项目的需求。

M----代表Model:对应于JavaBean,处理的是业务逻辑和实体模型

V-----代表View:对应于Activity,处理View的绘制和用户交互的操作

P-----代表presenter:这是新加的一个中间层,负责完成view和Model的交互

MVP的业务流程是,view与presenter相互交互,presenter操作model的数据,在View的绘制显示数据页面,View本身不再直接操作model层的数据实体而是通过presenter来控制

下面写一个登陆有关的小demo:

先看包结构:

一、model层:

1、User是一个JavaBean,代码如下:

package com.my_project.test_mvp.model;

/**
 * Created by com_c on 2018/8/22.
 */

public class User {
    private String userName;
    private String password;

    public User() {
    }

    public User(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

2、UserLoginEvent是登陆的时候作出的业务操作,这个类放到Model层就是因为它是登录的业务类,根据类别的划分,业务逻辑和实体类JavaBean是放在model层里,那么登陆---当然就是拿到账号密码跑网络请求接口,代码如下
 

package com.my_project.test_mvp.model;

import com.my_project.test_mvp.model.User;
import com.my_project.test_mvp.presenter.IUserLogin;
import com.my_project.test_mvp.presenter.OnLoginListener;

/**
 * Created by com_c on 2018/8/22.
 */

public class UserLoginEvent implements IUserLogin {
    @Override
    public void login(final String userName, final String pwd, final OnLoginListener onLoginListener) {
        //开启子线程登录
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (userName.equals("123") && pwd.equals("123")) {
                    onLoginListener.loginSuccess(new User(userName,pwd));
                } else {
                    onLoginListener.loginFailed();
                }
            }
        }.start();
    }
}

3、登陆成功或者失败的接口回调

package com.my_project.test_mvp.presenter;

import com.my_project.test_mvp.model.User;

/**
 * Created by com_c on 2018/8/22.
 */

public interface OnLoginListener {
    void loginSuccess(User user);
    void loginFailed();
}

二、view层:

view对应的就是Activity,MVP的规则是要通过presenter用model的数据来刷新view的界面,这就是说view不能自己去控制刷新的操作,而且,我们将login的访问服务器操作放在了model层,那用户输入的账号密码怎么传给model层,所以我们要在view层所在的activity中提供收集数据的方法,通过接口回调(也就是presenter的控制层)传给model层,在登录的这个模块中需要的方法有:

  1. getUserName();
  2. gerPassword();

然后在跑网络请求的时候一般会给一个进度条的友好提醒,所以再加上

  1. showLoading();
  2. hideLoading();

当用户输入账号密码要跳转下一个页面的时候,startActivity这一步当然说放在哪里都可以,不过跳转activity嘛,就在activity中实现代码应当是最合适的地方,也符合逻辑,所以再加两个登录成功与失败的方法

  1. toNextActivity();
  2. showFailError();

一般在登录页面会有一个一键清除输入框的取消按钮,所以我们一并实现两个清除账号密码的方法,接口的方法就是:

package com.my_project.test_mvp.view;

/**
 * Created by com_c on 2018/8/22.
 */

public interface IUserLoginV {
    String getUserName();

    String getPassword();

    void clearUserName();

    void clearPassword();

    void showLoading();

    void hideLoading();

    void toNextActivity();

    void showFailedError();
}

    这就是view的接口,这个view的接口是做什么用的?是给代表着View界面的activity实现做接口的,也就是说activity中的功能操作,view的接口都应该给出具体让activity实现的方法,比如说:

  1. 这个模块功能的操作,需要什么东西,拿登录来说,就是需要账号和密码(getUserName和getPassword)
  2. 这个操作的结果是什么,登录的结果当然是成功和失败(toNextActivity和showFailError)
  3. 操作过程中的友好交互,也就是给个进度条的提醒

然后我们看下View接口的实现类,也就是activity的样子

package com.my_project.test_mvp.view;

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

import com.my_project.R;
import com.my_project.test_mvp.presenter.UserLoginPresenter;

/**
 * Created by com_c on 2018/8/22.
 */

public class TestMVPActivity extends AppCompatActivity implements View.OnClickListener, IUserLoginV {

    private EditText et_name, et_pwd;
    private Button btn_commit, btn_clean;
    private ProgressBar pBar;
    private UserLoginPresenter userLoginPresenter = new UserLoginPresenter(this);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvp);
        bindID();
        initView();
    }

    private void initView() {
        btn_commit.setOnClickListener(this);
        btn_clean.setOnClickListener(this);
    }

    private void bindID() {
        et_name = findViewById(R.id.et_name);
        et_pwd = findViewById(R.id.et_pwd);
        btn_commit = findViewById(R.id.btn_commit);
        btn_clean = findViewById(R.id.btn_clean);
        pBar = findViewById(R.id.pBar);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_commit:
                userLoginPresenter.login();
                break;
            case R.id.btn_clean:
                userLoginPresenter.clean();
                break;
        }
    }

    @Override
    public String getUserName() {
        return et_name.getText().toString().trim();
    }

    @Override
    public String getPassword() {
        return et_pwd.getText().toString().trim();
    }

    @Override
    public void clearUserName() {
        et_name.setText("");
    }

    @Override
    public void clearPassword() {
        et_pwd.setText("");
    }

    @Override
    public void showLoading() {
        pBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        pBar.setVisibility(View.GONE);
    }

    @Override
    public void toNextActivity() {
        Toast.makeText(TestMVPActivity.this, "成功跳转", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError() {
        Toast.makeText(TestMVPActivity.this, "账号密码有误", Toast.LENGTH_SHORT).show();
    }
}

三、presenter层:

presenter是拿着model层的数据,去控制view层的显示,再结合现实中模块的功能,当前登录的话,就是一个login和clean

package com.my_project.test_mvp.presenter;

import com.my_project.test_mvp.model.OnLoginListener;
import com.my_project.test_mvp.model.UserLoginEvent;
import com.my_project.test_mvp.model.User;
import com.my_project.test_mvp.view.IUserLoginV;

/**
 * Created by com_c on 2018/8/22.
 */

public class UserLoginPresenter {
    private UserLoginEvent userLoginEvent;
    private IUserLoginV userLoginView;

    public UserLoginPresenter(IUserLoginV iUserLoginV) {
        this.userLoginView = iUserLoginV;
        this.userLoginEvent = new UserLoginEvent();
    }

    private android.os.Handler mHandler = new android.os.Handler();;

    public void login() {
        userLoginView.showLoading();
        userLoginEvent.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
            @Override
            public void loginSuccess(User user) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.toNextActivity();
                        userLoginView.hideLoading();
                    }
                });

            }

            @Override
            public void loginFailed() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.showFailedError();
                        userLoginView.hideLoading();
                    }
                });

            }
        });
    }

    public void clean() {
        userLoginView.clearUserName();
        userLoginView.clearPassword();
    }
}

可以看到,我们是在Activity中引用这个presenter层的,也就是View层调用presenter层,那么presenter层去model层拿数据在哪里体现,presenter层的构造方法中拿到了用户在activity输入的账号密码,这是View层的接口提供给presenter的数据,而这些账号密码的数据又通通传递给了model层去做业务逻辑的操作,也就是model层中跑服务器接口,去真正login(),然后登录成功与否的反馈,又是通过model层调用去触发登录的接口回调,而在presenter层实现这个接口,presenter层拿到了接口回调的结果之后,再去触发View层的接口回调,这时候,View层(也就是Activity)实现了这个接口方法,拿到方法再去执行对应的操作,

猜你喜欢

转载自blog.csdn.net/dream_caoyun/article/details/81944048
MVP