MVP基础架构

  • MVP 是什么
  • 基础架构
  • 登录例子
  • MVP的优缺点

一、MVP 是什么

MVP全名是 Model - View - Presenter,Model 层负责处理数据,View 层负责处理界面,Presenter 层负责连接 Model 层和 View 层,处理业务逻辑。Model 层和 View 层不能直接交互,需要在 Presenter 层中通过接口进行交互

  • Model层负责处理数据,如 JavaBean 、网络请求的封装、数据库、SharedPreference 等
  • View层负责处理界面,一般指的是 Activity 或 Fragment,需要持有 Presenter 的引用
  • Presenter层负责处理业务逻辑,持有 Model 和 View 的引用,获取 Model 层得到的数据传给 View 展示

二、基础架构

Presenter 层

Presenter 层负责连接 Model 层和 View 层,Model 层和 View 层不能直接交互,需要通过 Presenter 层进行交互。

所以 Presenter 需要持有 Model 和 View 的引用。attachView() 是为了获取 View 的引用,detachView() 是为了防止 Presenter 一直持有 View 的引用,导致内存泄露。需不需要将 M 层抽象成具体的 IModel 接口待定。

另一种写法:也可以将 view 声明为弱引用,用动态代理的方式判断 view 是否被系统回收从而避免每次都要判断 view 是否为空。

public interface IPresenter<V extends IView> {

    /**
     * 绑定View
     */
    void attachView(V view);

    /**
     * 解绑View
     */
    void detachView();

}

public class BasePresenter<V extends IView> implements IPresenter<V> {

    protected V view;

    @Override
    public void attachView(V view) {
        this.view = view;
    }

    @Override
    public void detachView() {
        view = null;
    }

}

View 层,以 Activity 为例

View层负责处理界面,抽象一些常用的 UI 方法,如显示加载,隐藏加载等

public interface IView {
    /**
     * 显示加载
     */
    void showLoading();

    /**
     * 隐藏加载
     */
    void hideLoading();

}

View层需要持有 Presenter 的引用,提供给子类初始化 Presenter 的抽象方法。在 onCreate() 中初始化Presenter 并绑定 View,在 onDestroy() 解绑 View

public abstract class BaseActivity<P extends IPresenter> extends AppCompatActivity implements IView{

    protected P presenter;

    /**
     * 初始化 Presenter
     */
    public abstract P initPresenter();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (null == presenter) {
            presenter = initPresenter();
        }
        // 绑定 View
        if (null != presenter) {
            presenter.attachView(this);
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 解绑 View
        if (null != presenter) {
            presenter.detachView();
        }
    }

    @Override
    public void showLoading() {

    }

    @Override
    public void hideLoading() {

    }

}

三、登录例子
输入账号密码,点击按钮登录。界面:

View 层负责获取用户输入的账号密码,Presenter 负责处理登录逻辑

interface LoginContract {

    interface View: IView{
        val tel: String
        val password: String
    }

    interface Presenter: IPresenter<View>{
        fun login(tel: String, password: String)
    }
}

具体 Presenter

class LoginPresenter : BasePresenter<LoginContract.View>(), LoginContract.Presenter{

    override fun login(tel: String, password: String) {
        view.showLoading()
        LoginModel().login(tel, password, object : LoginModel.loginListener{
            override fun onLoginSuccess() {
                view.hideLoading()
                view.onLoginSuccess()
            }
        })
    }
}

具体 View

class MainActivity: BaseActivity<LoginContract.Presenter>(), LoginContract.View {
    override val tel: String
        get() = et_tel.text.toString()
    override val password: String
        get() = et_password.text.toString()

    override fun initPresenter() = LoginPresenter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btn_login.setOnClickListener { presenter.login(tel, password) }
    }

    override fun onLoginSuccess() {

    }
}

四、MVP的优缺点
MVP的优点:
Model 层和 View 层完全解耦,它们在Presenter 层中通过接口进行交互,如在 LoginPresenter 中通过 LoginModel 登录获取用户数据,然后通过 LoginView 显示数据

MVP的缺点:
要增加很多接口类和 Presenter 类
可以通过 Contract 协议类减少接口数量,简单的业务逻辑可以复用 Presenter

推荐阅读更多精彩内容