Android mvp之P,V的封装

本文介绍如何在Android的MVP模式中封装Presenter和View,以RegisterFragment为例,创建RegisterContract接口,包括View和Presenter的接口。BaseContract作为公共契约,定义了通用方法如显示错误、加载进度等。RegisterContract继承自BaseContract,并添加注册相关的方法。通过PresenterFragment抽象类实现BaseContract.View,处理通用方法,并在子类中初始化Presenter。RegisterFragment继承PresenterFragment并实现RegisterContract.View,完成特定业务逻辑。
摘要由CSDN通过智能技术生成

在MVP模式中,我们知道通常Presenter层会与View层进行绑定联系。由Presenter层控制View,同时,View层也将调用Presenter进行逻辑及界面显示。View层通常是我们的Fragment或者Activity,那么本文就注册的界面(RegisterFragment) 对最顶部的Presenter,View一直到BasePresenter,BaseView进行封装。

首先,我们创建一个RegisterFragment和一个RegisterPresenter,它们必须按照一定得规矩进行。(此处RegisterFragment即为View层)

So我们创建一个接口文件RegisterContract,其中包含两个内部接口View以及Presenter

那么接口文件中应该有什么方法呢?

在Presenter中,我们应该有注册的方法Register。也应该有presenter的开启和销毁方法(start,destroy)。

在View中,我们应该有注册成功后的回掉方法用以告诉Fragment我们注册成功可以开始下一步操作。

那么你会发现在这些方法中并非所有方法都是RegisterFragment或者RegisterPresenter共有的,so我们进行提取,我们将不属于Register注册功能特有的方法提取到BaseContract中。于是,我们的RegisterContract可以写了

//RegisterContract的特有契约 interface RegisterContract { interface View{ //注册成功 void registerSuccess(); } interface Presenter{ //发起一个注册 void register(String phone,String name,String password); }

}(此处RegisterContract未完成,还未继承自基类Contract) 那么接下来该写BaseContract了,在此之前我们想一个问题,每个View层中都需要一个Presenter对吧,那么我们就需要在View层中也就是RegisterFragment中设置Presenter,也就是将View层与Presenter层进行绑定,所以我们需要在基本契约(BaseContract)中为View添加一个方法setPresenter(Presenter)

我们所有的Presenter都必须继承BaseContract.Presenter的实现类BasePresenter(一会儿新建),但它是什么种类,是RegisterPresenter还是LoginRegister我们不知道,所以在setPresenter是里面的参数必须是一个泛型,那么这个泛型我们就需要在创建View接口时为它定义好,也就是T extend Presenter,所以我们可以写BaseContract了。

/**

  • MVP格式中公共的基本契约 */ public interface BaseContract { interface View<T extends Presenter> {//此处的presenter即为下面定义的Presenter //公共的:显示一个字符串错误 void showError(@StringRes int str); //公共的:显示进度条 void showLoading(); //支持设置一个Presenter void setPresenter(T presenter); } interface Presenter { //共同的开始方法 void start(); //共同的销毁触发 void destroy(); } } 公共契约BaseContract有了,我们就可以更改我们的特有契约RegisterContract了,我们让它的View接口以及Presenter接口继承自BaseContract中的即可

public interface RegisterContract { interface View extends BaseContract.View<Presenter>{//此处的presenter即为下面定义的Presenter,因为下面有继承,你懂的~ //注册成功 void registerSuccess(); }

interface Presenter extends BaseContract.Presenter {
    //发起一个注册
    void register(String phone,String name,String password);
}

} 契约(接口)有了,那么我们就应该实现它了。首先我们来实现View层,前面提到了,此例的View即我们的RegisterFragment,那么我们就让RegisterFragment实现RegisterContract.View

RegisterFragment implements RegisterContract.View,写上后面的Implements发现报红,我们必须实现RegisterContract.View里面的所有方法,其中包括了registerSuccess()以及showError(),shwLoading(),setPresenter()。很显然,除了registerSuccess()方法外,其他两个方法我们不希望它们出现在我们的RegisterFragment中,因为我们在这里实现也代表着将来的loginFragment以及各种基于Base契约开发的Fragment都必须去实现除了registerSuccess外的所有方法。so我们要将showError(),showLoading(),setPresenter()提取出来,提取到一个基本的带有presenter的fragment中去是实现,于是我们的PresenterFragment诞生了! public class PresenterFragment extends Fragment implements BaseContract.View<> 由于我们的BaseContract.View在编写的时候是带有Presenter泛型的,那么此处也应该传递一个泛型,去观察BaseContract发现此处是一个继承自BaseContract.Presenter的泛型,所以我们在PresenterFragment后面定义一个泛型<Presenter extends BaseContract.Presenter>,在BaseContract.View后面填入<Presenter> public class PresenterFragment<Presenter extends BaseContract.Presenter> extends Fragment implements BaseContract.View<Presenter> 接下里就是实现公共契约中的方法啦 showError(),shwLoading(),setPresenter()。

紧接着,我们需要一个Presenter变量,所以我们定义一个泛型为Presenter的变量mPresenter,并在setPresenter中赋值w

 

在此类中,除了我们应该实现的方法外,我们还没有对Presenter进行初始化,那么我们就在onAttach中对它进行初始化

@Override public void onAttach(Context context) { super.onAttach(context);

//在界面onAttach之后就触发初始化Presenter
Log.d("ONATTACH", "初始化presenter");
initPresenter();

} 有初始化的调用,但是没有初始化的实现,我们需要将initPresenter实现,但是可以在此类实现吗?

不可以,此类为RegisterFragment的基类,此类取得的Presenter并非RegisterPresenter,所以我们将初始化的实现一起抛给registerFragment去实现,所以我们在initPresenter前加上abstract

那么我们也必须在类定义前加上abstract

最终的presenterFragment完成

public abstract class PresenterFragment<Presenter extends BaseContract.Presenter> extends Fragment implements BaseContract.View<Presenter> {

protected Presenter mPresenter;
​
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    //在界面onAttach之后就触发初始化Presenter
    Log.d("ONATTACH", "初始化presenter");
    initPresenter();
}
​
/**
 * 初始化Presenter
 * @return Presenter
 * */
protected abstract Presenter initPresenter();
​
@Override
public void showError(int str) {
    //显示错误
    Application.showToast(str);
}
​
@Override
public void showLoading() {
    //TODO 显示一个Loading
}
​
@Override
public void setPresenter(Presenter presenter) {
    //View中赋值Presenter
    mPresenter = presenter;
}

} 有了PresenterFragment我们就可以让RegisterFragment继承它了。

注:里面的泛型,应该传入一个BaseContract.Presenter的子类,而对于我们的RegisterFragment来说,很显然,RegisterContract.Presenter就是我们需要的Presenter

public class RegisterFragment extends PresenterFragment<RegisterContract.Presenter> implements RegisterContract.View 还记得父类抛给我们的方法吗?该实现了!

那么首先我们就要重写initPresenter,在该方法中我们该真正实现Presenter初始化了,要在其中初始化我们Register界面的Presenter,那么我们就需要一个实现类来初始化它。So我们新建一个类RegisterPresenter

public class RegisterPresenter implements RegisterContract.Presenter

注意:这里是实现了RegisterContract.Presenter中的所有契约,而RegisterContract是BaseContract的子类,所以我们需要将共有的BaseContact.Presenter中的方法以及Register.Contract里的特有方法全部实现,很明显,我们不应该这样做,所以我们再提取一个基本实现类出来,所以我们新建一个实现类BasePresenter

public class BasePresenter<T extends BaseContract.View> implements BaseContract.Presenter 
注意:这里必须传入一个泛型,我们不知道子类会是个什么类型的View,但可以确定所有的View都是BaseContract.View的子类,所以我们传入T extends BaseContract.View

在BasePresenter中,我们的第一个方法就是构造方法呢。我们希望在Presenter创建的时候就将Presenter和View进行绑定,那么我们就需要在构造方法中绑定,所以我们写一个setView方法并在构造方法中调用(先定义一个泛型View的变量方便后面使用)

private T mView;
public BasePresenter(T view) {
    setView(view);
}
/**
 * 将View与Presenter绑定
 */
protected void setView(T view) {
    this.mView = view;

    //下面这个setPresenter在BaseContract中申明的方法,因为我们需要获取到View具体的类型,所以在最顶层的RegisterFragment中重写,并在这个地方调用
    this.mView.setPresenter(this);
}

接下来我们需要给子类提供一个getView的方法,将我们得到的View传给后面继承我们的Presenter子类。这样子类例如RegisterPresenter才可以自己得到它需要控制的View。

所以这个流程其实是  RegisterPresenter在构造函数中传入一个RegisterContract.View,然后就是调用父类BasePresenter的构造方法  -->  BasePresenter构造方法中调用setView   -->  在setView中将RegisterPresenter传过来的view赋值到我们最开始定义的mView并且调用mView的setPresenter方法将Presenter与View进行绑定

最后再添加上我们基类约定的方法start和destroy

所以最后的BasePresenter就是这样

public class RegisterPresenter extends BasePresenter<RegisterContract.View>
        implements RegisterContract.Presenter, DataSource.Callback<User> {
    public RegisterPresenter(RegisterContract.View view) {
        super(view);
    }

    @Override
    public void register(String phone, String name, String password) {
        //调用开始方法,在start中默认启动了Loading
        start();

        //得到View接口
        RegisterContract.View view = getView();

        //校验
        if (!checkMobile(phone)) {
            //提示手机号不合法
            view.showError(R.string.data_account_register_invalid_parameter_mobile);
        } else if (name.length() < 2) {
            //姓名需要大于两位
            view.showError(R.string.data_account_register_invalid_parameter_name);
        } else if (password.length() < 6) {
            //密码需要大于6位
            view.showError(R.string.data_account_register_invalid_parameter_password);
        } else {
            //进行网络请求
            //构造model,进行请求调用
            RegisterModel model = new RegisterModel(phone, password, name);
            //进行网络请求并设置回送口为自己
            AccountHelper.register(model, this);
        }
    }


    /**
     * 检查手机号是否合法
     *
     * @param phone 手机号码
     * @return 合法为true
     */
    @Override
    public boolean checkMobile(String phone) {
        //手机号不为空并且满足相应格式
        return !TextUtils.isEmpty(phone)
                && Pattern.matches(Common.Constance.REGES_MOBILE, phone);
    }

    @Override
    public void onDataLoaded(User user) {
        //当网络请求成功,注册好了,回送一个用户信息回来
        //告知界面,注册成功
        final RegisterContract.View view = getView();
        if (view == null)
            return;
        //此时是从玩过回送回来的,并不保证属于主线程状态
        //强制执行在主线程中
        Run.onUiAsync(new Action() {
            @Override
            public void call() {
                //调用主界面的注册成功
                view.registerSuccess();
            }
        });

    }

    @Override
    public void onDataNotAvaliable(final int strRes) {
        //网络请求告知注册失败
        final RegisterContract.View view = getView();
        if (view == null)
            return;
        //此时是从玩过回送回来的,并不保证属于主线程状态
        //强制执行在主线程中
        Run.onUiAsync(new Action() {
            @Override
            public void call() {
                //调用主界面的注册成功
                view.showError(strRes);
            }
        });

    }
}

最后我们在RegisterPresenter中让它继承BasePresenter~

封装基本完成~有问题下面留言哦~

MVP新手,大神勿喷,如有不对的地方,欢迎指正!!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值