架构师学习--MVP

一、概述

MVP相比较于MVC ,能够解决MVC的内存泄漏问题。并且业务模块分的更加明确。

M:model层 一般指javabean对象 。当然也可以处理业务逻辑

V:activity 发起请求,交给presenter处理

P:Presenter层 负责将activity的请求交给model层处理,也可以自己处理。并将处理结果返回给view层

 

比如我们真实的业务中,登陆请求。下面看看该如何封装一个mvp框架·。

二、使用

1、创建M层,V层,P层基类

(1)Model层基类BaseModel,持有Presenter层的引用,并且提供契约接口,供子类实现。代码如下:

/**
 * 需要拿到契约CONTRACT
 * 使用抽象类 子类必须重写抽象类的抽象方法
 * @param <P>
 */
public abstract class BaseModel<P extends BasePresenter,CONTRACT> {
    protected P p;

    public BaseModel(P p) {
        this.p = p;
    }

    public abstract CONTRACT getContract();
}

(2)View层基类BaseView,持有Presenter层引用,并且提供契约接口,供子类实现。代码如下:

package com.example.mvpdemo.base;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;

/**
 * view层基类
 * 需要交给P层任务 需要将契约传给P层,P层就可以操作view层
 * @param <P>
 */
public abstract class BaseView<P extends BasePresenter,CONTRACT> extends AppCompatActivity {
    protected P p;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //获取子类的Presenter
        p = getPresenter();
        //p层绑定view层
        p.bindView(this);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        p.uunBindView();
    }

    public abstract CONTRACT getContract();
    public abstract P getPresenter();
    public abstract int error();
}

(2)Presenter层基类BasePresenter,持有View层和Model层引用,并且提供契约接口,供子类实现。代码如下:

package com.example.mvpdemo.base;

import java.lang.ref.WeakReference;

/**
 * 需要将view任务交给model层
 * 需要将结果通知view层更新
 */
public abstract class BasePresenter<V extends BaseView, M extends BaseModel, CONTRACT> {

    protected M m;

    //当前view弱引用,防止view层内存泄漏
    private WeakReference<V> vWeakReference;

    public BasePresenter() {
        m = getModel();
    }

    /**
     * 绑定view
     */
    public void bindView(V v) {
        vWeakReference = new WeakReference<>(v);

    }

    public V getView() {
        if (vWeakReference != null) {
            return vWeakReference.get();
        }

        return null;
    }

    /**
     * 、
     * 解绑view
     */
    public void uunBindView() {
        if (vWeakReference != null) {
            vWeakReference.clear();
            vWeakReference = null;
            System.gc();
        }
    }

    public abstract CONTRACT getContract();
    //子类实现中拿到model实例
    public abstract M getModel();
}

该类中使用弱引用的形式持有view层的引用。并且提供添加弱引用和解除弱引用的方法。这样就能够够解决内存泄露的问题。

(4)创建网络请求返回结果实体基类BaseBean,主要记录网络请求的状态,错误码及错误信息。代码如下:

package com.example.mvpdemo.base;

public class BaseBean {
    private String msg;
    private boolean isSuccess;
    private int errorCode;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public boolean isSuccess() {
        return isSuccess;
    }

    public void setSuccess(boolean success) {
        isSuccess = success;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(int errorCode) {
        this.errorCode = errorCode;
    }
}

2、创建登陆模块各层实现类

(1)创建契约接口类LoginContract,主要提供了供子类去实现的契约接口,代码如下:

package com.example.mvpdemo.login;


import com.example.mvpdemo.base.BaseBean;

/**
 * 用于协商view层 model层 presenter层业务
 */
public interface LoginContract {

    /**
     * 处理登陆请求
     */
    interface Model<T extends BaseBean>{
        void excuteLogin(String userName,String pwd) throws Exception;
    }

    /**
     * 接受处理结果更新界面
     * 做约束需要集成baseBean
     */
    interface View<T extends BaseBean>{
        void handlerResult(T t);
    }

    /**
     * 接受view的请求交给model层处理
     * 接受model层处理结果返回给view层
     */
    interface Presenter<T>{
        void requestLogin(String userName,String pwd);
        void responseResult(T t);
    }


}

(2)创建LoginActivity。继承BaseView,并重写getContract()方法和getPresenter()方法。代码如下:

package com.example.mvpdemo.login;

import android.os.Bundle;
import android.support.annotation.Nullable;

import com.example.mvpdemo.base.BaseView;
import com.example.mvpdemo.bean.LoginBean;

public class LoginActivity extends BaseView<LoginPresenter,LoginContract.View> {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        p.getContract().requestLogin("qq","1111");
    }

    @Override
    public LoginContract.View getContract() {
        return new LoginContract.View<LoginBean>() {
            @Override
            public void handlerResult(LoginBean loginBean) {

            }
        };
    }

    @Override
    public LoginPresenter getPresenter() {
        return new LoginPresenter();
    }

    @Override
    public int error() {
        return 0;
    }
}

注意这里的getContract()方法,当我们的请求结果返回成功后,由于P层可以通过getView方法获取当前操作的·view。那么可以调用view.getContract()创建接口实例。接着就可以将结果进行返回。显然是面向接口编程。

(3)创建LoginModel,继承BaseView,并重写getContract()方法。代码如下:

package com.example.mvpdemo.login;

import com.example.mvpdemo.base.BaseModel;
import com.example.mvpdemo.bean.LoginBean;

public class LoginModel extends BaseModel<LoginPresenter,LoginContract.Model> {
    public LoginModel(LoginPresenter loginPresenter) {
        super(loginPresenter);
    }

    @Override
    public LoginContract.Model getContract() {
        return new LoginContract.Model<LoginBean>() {
            @Override
            public void excuteLogin(String userName, String pwd)  throws Exception{
                LoginBean loginBean = new LoginBean();
                loginBean.setPwd("1111");
                loginBean.setUserName("qb");
                if(userName.equalsIgnoreCase("qb")){
                    //交给P层
                    p.getContract().responseResult(loginBean);
                }else{
                    p.getContract().responseResult(null);
                }
            }
        };
    }


}

同样,由于P层持有M层的引用。那么可以调用model.getContract()创建接口实例。并将请求交给Model层处理。

(4)创建LoginPresenter,继承BasePresenter。并重写getContract()和getModel()方法。代码如下:

package com.example.mvpdemo.login;

import com.example.mvpdemo.base.BasePresenter;
import com.example.mvpdemo.bean.LoginBean;

public class LoginPresenter extends BasePresenter<LoginActivity, LoginModel, LoginContract.Presenter> {
    @Override
    public LoginContract.Presenter getContract() {
        return new LoginContract.Presenter<LoginBean>() {
            @Override
            public void requestLogin(String userName, String pwd) {
                try {
                    //1、交给model层
                    m.getContract().excuteLogin(userName, pwd);
                    //2、返回结果自己处理
                    //responseResult();
                    //3、写一个处理类返回结果 比如HttpEngine
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void responseResult(LoginBean loginBean) {
                //拿到view层契约,是一个接口,在activity中已经实现。面向接口编程
                getView().getContract().handlerResult(loginBean);
            }
        };
    }

    @Override
    public LoginModel getModel() {
        return new LoginModel(this);
    }
}

这里m.getContract().excuteLogin(userName, pwd),把处理逻辑交给M层实现;getView().getContract().handlerResult(loginBean),将结果返回给V层。

三、内存泄漏验证

1、首先我们先把baseView的这一段代码注释掉:

@Override
    protected void onDestroy() {
        super.onDestroy();
        //p.unBindView();
    }

2、运行程序,点击按钮,日志如下,我这里返回的结果是我自己模拟的数据

3、点击内存分析工具profiler。进入界面视图。此时将activity关闭,进行以下步骤:

4、第一步、第二步完成后进入以下界面,选中packet模式,找到com包名,可以发现,存在我们的LoginActivity。说明发生了内存泄漏

5、将之前注释的代码恢复,再次执行以上步骤,发现没有发现我们的包名,这样内存泄漏就得到了解决

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值