MVP详细解析以及使用方法

github地址:https://github.com/libin7278/MPV-example
需要结合开源项目理解MVP并逐步学会使用,本开源项目正在逐步完善中

MVP(Module View Controller)是MVC的演进版本,所以首先介绍一下MVC(Module View Presenter)

MVC

MVC 是一种框架模式而非设计模式。

框架:用来对软件设计进行分工。
设计模式:小技巧,对具体问题提出解决方案,太高代码复用率,降低耦合度。

MVC在Android中的实现

View层一般采用XMl文件进行界面的描述;
Module则对应本地数据文件或者网络获取的数据体;
Controller部分则由Activity承担;
这个框架并非我们自己完成的,而是由framework给我们搭建好并提供给我们。

MVP

解除了View和Module的耦合,同时又带来了良好的可扩展性,可测试性。
使用MVP的好处:UI可能随时改变,如果业务逻辑耦合在View中,UI修改会导致我们重新抽离View中的业务逻辑。MVP刚好帮我们完成了逻辑抽离。

区别

(1)MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。
(2)还有一点就是Presenter与View之间的交互是通过接口的。
首先看一下实现了MVP的Activity出来的效果,这是一个最简单的用户名登录

MVC特点
1.用户可以向View发送指令,再由View直接要求Modle改变状态
2.用户可以直接向Controller发送指令,再由Controller发送View
3.Controller起到事路由的作用,同时业务逻辑都部署在Controller
这里写图片描述

MVVM特点
View和Model进行双向绑定,两者之间有一方发生变化则会反映到另一方上。ViewModle要做的只是业务逻辑处理,以及修改View或者Modle的状态。
这里写图片描述

MVP特点
View更新通过Presenter,View和Modle不直接联系
这里写图片描述

package com.mvp.libin.mvp_example;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.mvp.libin.mvp_example.base.MVPBaseActivity;
import com.mvp.libin.mvp_example.bean.User;
import com.mvp.libin.mvp_example.presenter.UserLoginPresenterB;
import com.mvp.libin.mvp_example.view.IViewUserLogin;

/**
 * Created by libin on 16/11/9.
 */

public class ActivityBUserLogin extends MVPBaseActivity<IViewUserLogin,UserLoginPresenterB>implements IViewUserLogin {
    private EditText et_usernam,et_userpassword;
    private ProgressBar pb;
    private Button btn_login,btn_clear;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        findViewById();

        //登录
        btn_login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.login();
            }
        });

        //清除
        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.clear();
            }
        });

    }

    @Override
    protected UserLoginPresenterB createPresenter() {
        return new UserLoginPresenterB(this);
    }

    private void findViewById() {
        et_userpassword = (EditText) findViewById(R.id.et_userpassword);
        et_usernam = (EditText) findViewById(R.id.et_usernam);

        btn_login = (Button) findViewById(R.id.btn_login);
        btn_clear = (Button) findViewById(R.id.btn_clear);

        pb = (ProgressBar) findViewById(R.id.pb);
    }

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

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

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

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

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

    @Override
    public void hideLoading() {
        pb.setVisibility(View.INVISIBLE);
    }

    @Override
    public void toMainActivity(User user) {
        Toast.makeText(this, user.getUsername() + " login success , to MainActivity", Toast.LENGTH_SHORT).show();
    }


    @Override
    public void showFailedError() {
        Toast.makeText(this, " login failed ", Toast.LENGTH_SHORT).show();
    }
}

首先考虑一下View 我们这个登录都需要啥?
然后定义出所有需要的方法

package com.mvp.libin.mvp_example.view;

import com.mvp.libin.mvp_example.bean.User;

/**
 * Created by libin on 16/11/8.
 */

public interface IViewUserLogin {
    String getUserName();

    String getPassword();

    void clearUserName();

    void clearPassword();

    void showLoading();

    void hideLoading();

    void toMainActivity(User user);

    void showFailedError();
}

实现模型所需要的接口

public interface IUserModel {
    public void login(String username, String password, OnLoginListener loginListener);
}

实现模型所需要的接口

public interface OnLoginListener {
    void loginSuccess(User user);

    void loginFailed();
}

具体的业务在module完成

public class UserModel implements IUserModel {
    @Override
    public void login(final String username, final String password, final OnLoginListener loginListener) {
        //模拟子线程耗时操作
        new Thread()
        {
            @Override
            public void run()
            {
                try
                {
                    Thread.sleep(2000);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                //模拟登录成功
                if ("123".equals(username) && "123".equals(password))
                {
                    User user = new User();
                    user.setUsername(username);
                    user.setPassword(password);
                    loginListener.loginSuccess(user);
                } else
                {
                    loginListener.loginFailed();
                }
            }
        }.start();
    }
}

将View和modle关联到一起

public class UserLoginPresenterB extends BasePresenter<IViewUserLogin> {
    private IUserModel userBiz;
    private IViewUserLogin userLoginView;
    private Handler mHandler = new Handler();

    public UserLoginPresenterB(IViewUserLogin userLoginView)
    {
        this.userLoginView = userLoginView;
        this.userBiz = new UserModel();
    }

    public void login()
    {
        userLoginView.showLoading();
        userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener()
        {
            @Override
            public void loginSuccess(final User user)
            {
                //需要在UI线程执行
                mHandler.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        userLoginView.toMainActivity(user);
                        userLoginView.hideLoading();
                    }
                });

            }

            @Override
            public void loginFailed()
            {
                //需要在UI线程执行
                mHandler.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        userLoginView.showFailedError();
                        userLoginView.hideLoading();
                    }
                });

            }
        });
    }

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

接下来我们来看一下基类的实现,之所以要用弱引用,是因为Presenter经常执行一些耗时的操作,而presenter持有Activity的强引用,如果在请求结束之前Activity被销毁,网络请求还没有返回,导致presenter一直持有activity的对象,使得activity对象无法被回收,此时发生内存泄漏。

package com.mvp.libin.mvp_example.base;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

/**
 * Created by libin on 16/11/8.
 */

public class BasePresenter<T> {
    protected Reference<T> mViewRef;  //View接口类型的弱引用

    /**
     * 建立关联
     * @param view
     */
    public void attachView(T view){
        mViewRef = new WeakReference<T>(view);
    }

    /**
     * 获取View
     * @return
     */
    protected T getView(){
        return mViewRef.get();
    }

    /**
     * 判断是否与View建立关联
     * @return
     */
    public boolean isViewAttach(){
        return mViewRef != null && mViewRef.get() != null;
    }

    /**
     * 解除关联
     */
    public void detechView(){
        if(mViewRef != null){
            mViewRef.clear();
            mViewRef = null;
        }
    }
}
public abstract class MVPBaseActivity<V,T extends BasePresenter<V>> extends Activity{
    protected T mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mPresenter = createPresenter(); //创建Presenter

        mPresenter.attachView((V) this); //View与Presenter建立关联
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPresenter.detechView();  //解除关联
    }

    protected abstract T createPresenter();
}

扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~
扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~
扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~

猜你喜欢

转载自blog.csdn.net/github_33304260/article/details/53161277
今日推荐