MVP架构由浅入深篇二(进阶版)

MVP架构由浅入深篇二(进阶版)

前言:在MVP基础版的讨论中我们发现了基础版MVP存在的不足之处,1.通用性差;2.存在漏洞;3.有重复代码。在本篇内容中,我们会对基础版MVP进行升级,到进阶版MVP解决基础版MVP遇到的问题。


目录

MVP架构由浅入深篇二(进阶版)

一、在Presenter层调用MvpView接口方法时可能出现空指针异常

1.新增Callback接口

2.新增BaseView接口

3.新增BasePresenter类

4.新增BaseActivity

5.MvpCallback修改

6.MvpView的修改

7.MvpPresenter修改

8.MianActivity修改


 

一、在Presenter层调用MvpView接口方法时可能出现空指针异常

在Presenter层因为需要给UI层反馈数据,所以持有View层的实例,然后通过实例回调MvpView接口的回调方法。但是如果此使Activity突然异常退出,则view就会出现空指针异常,在MainActivity中有这一行代码:presenter = new MvpPresenter(this);其中this就是实例,如果程序退出就会产生空指针。

想要避免这种情况的发生就需要每次调用View前都知道宿主Activity的生命状态。

先看一下进阶版文件结构:建一个base包,里面创建基类用来继承

1.新增Callback接口

在基础版的MvpCallback接口中onSuccess(String data)方法,由于String类型限制了数据类型,所以我们新增Callback接口,采用泛型的方法,使调用者自己去规定接收的数据类型。

package com.example.mvpapplication;

public interface Callback<T> {
    /**
     * 数据请求成功
     * @param data 请求到的数据
     */
    void onSuccess(T data);

    /**
     *  使用网络API接口请求方式时,虽然已经请求成功但是由
     *  于{@code msg}的原因无法正常返回数据。
     */
    void onFailure(String msg);

    /**
     * 请求数据失败,指在请求网络API接口请求方式时,出现无法联网、
     * 缺少权限,内存泄露等原因导致无法连接到请求数据源。
     */
    void onError();

    /**
     * 当请求数据结束时,无论请求结果是成功,失败或是抛出异常都会执行此方法给用户做处理,通常做网络
     * 请求时可以在此处隐藏“正在加载”的等待控件
     */
    void onComplete();
}

2.新增BaseView接口

View接口中定义Activity的UI逻辑。因为有很多方法几乎在每个Activity中都会用到,例如显示和隐藏正在加载进度条,显示Toast提示等,索性将这些方法变成通用的。

package com.example.mvpapplication;

import android.content.Context;

public interface BaseView {
    /**
     * 显示正在加载view
     */
    void showLoading();

    /**
     * 关闭正在加载view
     */
    void hideLoading();

    /**
     * 显示提示
     * @param msg
     */
    void showToast(String msg);

    /**
     * 显示请求错误提示
     */
    void showErr();
}

3.新增BasePresenter类

Presenter类主要是中间层,负责与Model和View打交道,由于上面我们已经定义好了BaseView,所以我们希望BasePresenter中View都是BaseView。

package com.example.mvpapplication;

public class BasePresenter <V extends BaseView>{
    /**
     * 绑定的view
     */
    private V mvpView;
    /**
     * 获取连接的view
     */
    public V getView(){
        return mvpView;
    }
    /**
     * 绑定view,一般在初始化中调用该方法
     */
    public void attachView(V mvpView) {
        this.mvpView = mvpView;
    }

    /**
     * 断开view,一般在onDestroy中调用
     */
    public void detachView() {
        this.mvpView = null;
    }

    /**
     * 是否与View建立连接
     * 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接
     */
    public boolean isViewAttached(){
        return mvpView != null;
    }
}

4.新增BaseActivity

BaseActivity主要是负责实现 BaseView 中通用的UI逻辑方法,如此这些通用的方法就不用每个Activity都要去实现一遍了。

package com.example.mvpapplication;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.widget.Toast;

public abstract class BaseActivity extends Activity implements BaseView {
    private ProgressDialog mProgressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mProgressDialog = new ProgressDialog(this);
        mProgressDialog.setCancelable(false);
    }

    @Override
    public void showLoading() {
        if (!mProgressDialog.isShowing()) {
            mProgressDialog.show();
        }
    }

    @Override
    public void hideLoading() {
        if (mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
    }

    @Override
    public void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showErr() {
        showToast("数据错误");
    }
}

5.MvpCallback修改

package com.example.mvpapplication;

import com.example.mvpapplication.base.Callback;

/**
 * callback负责presenter和model交互
 * 相当于:中介和房东交互接口
 */
public interface MvpCallback extends Callback<String> {}

由于MvpCallback extends Callback<String>,所以指定了该业务回调数据类型为String类型。

6.MvpView的修改

package com.example.mvpapplication;

import com.example.mvpapplication.base.BaseView;

/**
 * 这里相当于找房子的自己--对UI进行操作的接口
 */
public interface MvpView extends BaseView {

    /**
     * 展示数据
     * @param data
     */
    void showData(String data);

}

在MvpView中只用声明该业务特有的功能即可,因为其他通用功能已经在BaseView中声明好了。

7.MvpPresenter修改

package com.example.mvpapplication;

import com.example.mvpapplication.base.BasePresenter;

/**
 * 这里相当于中介的作用
 */
public class MvpPresenter extends BasePresenter<MvpView> {

    //因为中介要和雇主打交道,所以要声明MvpView
    private MvpView mView;

    public MvpPresenter(){}

    public MvpPresenter(MvpView view){
        this.mView = view;
    }

    /**
     * 相当于帮我找房子--请求数据
     * @param param
     */
    public void getData(String param){
        if (!isViewAttached())
            return;
        //显示正在加载进度条
        getView().showLoading();
        //调用Model请求数据
        MvpModel.getNetData(param, new MvpCallback(){
            @Override
            public void onSuccess(String data) {
                //调用view接口显示数据
                if (isViewAttached()){
                    getView().showData(data);
                }
            }

            @Override
            public void onFailure(String msg) {
                if (isViewAttached()){
                    getView().showToast(msg);
                }
            }

            @Override
            public void onError() {
                if (isViewAttached()){
                    getView().showErr();
                }
            }

            @Override
            public void onComplete() {
                if (isViewAttached()){
                    getView().hideLoading();
                }
            }
        });
    }
}

该类中只用实现getData方法即可,因为相关生命周期的绑定在BasePresenter中已经实现了。注意一点就是要指定BasePresenter的泛型参数类型为MvpView类型。

8.MianActivity修改

package com.example.mvpapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.example.mvpapplication.base.BaseActivity;

public class MainActivity extends BaseActivity implements MvpView{

    //进度条
    ProgressDialog progressDialog;
    TextView text;
    //找到中介
    MvpPresenter presenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = findViewById(R.id.text);
        //初始化进度条
        progressDialog = new ProgressDialog(this);
        progressDialog.setCancelable(false);
        progressDialog.setMessage("正在加载中...");
        //初始化presenter
        presenter = new MvpPresenter();
        //绑定View
        presenter.attachView(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //断开引用
        presenter.detachView();
    }

    /**
     * button事件
     */
    public void getData(View view){
        presenter.getData("normal");
    }
    public void getDataForFailure(View view){
        presenter.getData("failure");
    }
    public void getDataForError(View view){
        presenter.getData("error");
    }


    @Override
    public void showData(String data) {
        text.setText(data);
    }
}

到此为止,进阶版MVP框架已经改造完成了!可以看出代码复用技术虽然增加了代码量,但是使结构非常清晰,维护也更加轻松。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值