android MVP应用

android 谷歌官方MVP模式解读

一. 目录

二.MVP的含义

MVP在我上一个写关于地图的项目时候,在项目开始前也进行过学习,也在项目中也进行了应用。在今年暑假开始写西邮助手的时候,和小伙伴也是计划用MVP打框架。重新查阅资料发现,谷歌官方提供了一个MVP模式的Demo。所以对它进行了学习阅读,同时决定写一篇博客进行记录。

1.MVC模式

MVC即Model-View-Controller.即M:逻辑模型,V:视图模型,C:控制器

MVC模式下,系统框架的类库被划分为3种:模型(Model)、视图(View)、控制器(Controller)。模型对象负责建立数据结构和相应的行为操作处理。视图对象负责在屏幕上渲染出相应的图形信息展示给用户看。控制器对象负责截获用户的按键和屏幕触摸等事件,协调Model对象和View对象。

用户与视图交互,视图接收并反馈用户动作,视图把用户的请求传给相应的控制器,由控制器决定调用哪个模型,然后由模型调用相应的业务逻辑对用户请求进行加工处理,最后由模型对视图进行选择。即如下图所示
这里写图片描述

Android中的MVC
Android世界中也经常运用到MVC模式。
Activity对应视图界面也就是View层。
数据库文件,Sharedprefrence,内存缓冲,磁盘缓冲等数据内容对应Model层。
而Controller控制层基本上也由Activity层面来进行。

MVC中的不足
是的MVC是挺好的,但是它也有它的缺点,特别是针对Androi开发。

因为Android的特殊性,使得Activity对应了MVC中的V和C,同时担任两个角色,就有了类似“既当爹又当妈”的感觉,这显然就不符合软件设计原则的“单一职责”原则。但现实中是很多的APP代码中有这么的处境,特别是Androi原生的很多系统APK,某些Activity动则几千行代码。 所以越来越多的人选择MVP模式。

2.MVP

MVP即:Model-View-Presenter,MVP是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

MVP和MVC最大的区别就是 moder不能直接调用View,他们之间的通信是通过Presenter来进行的,所有的交互都发生在Presenter内部。两这区别如下:
这里写图片描述
这里写图片描述

在Android中应用到MVP,就是可以是V和P之间进行相互通信,P和M之间进行相互通信。简单举个下拉刷新的例子。
下拉刷新: V(刷新)–>P(通知M进行网络请求)–>M(进行网络请求);M(请求完毕)—>P(通知V加载更多)—>V(加载数据)。

三.原来的写法

我原来的写法是参考这一篇博客的
Android中MVP模式讲解及实践

1. 定义View接口,里面供提供p层抽象方法

public interface IWetherView {

    public void onInfoUpdate(String info);

    public void showWaitingDialog();

    public void dissmissWaitingDialog();
}

2. Activity或者Fragemt实现View接口

public class MainActivity extends AppCompatActivity implements IWetherView{

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

    @Override
    public void onInfoUpdate(String info) {

    }

    @Override
    public void showWaitingDialog() {

    }

    @Override
    public void dissmissWaitingDialog() {

    }
}

3. Model层的接口定义,里面供提供p层抽象方法

public interface IWetherModel {

    //提供数据
    public String getInfo();

    //存储数据
    public void setInfo(String info);
}

4. Model层实现

public class IWetherImpl implements IWetherModel {

    @Override
    public String getInfo() {
        return null;
    }

    @Override
    public void setInfo(String info) {

    }
}

5.Presenter代码及实现

Presenter中实现对V和M的调用,所以在P中要持有V和M的对象

public interface IWetherModel {

    IWetherModel mModel;
    IWetherView mView;

 //供View层调用,用来请求天气数据
    public void requestWetherInfo(){

    }
}

6.Presenter与View的通信

View—–>Presenter

public class MainActivity extends AppCompatActivity implements IWetherView{
    ......
    WetherPresenter mPresenter =WetherPresenter(this) ;
    ......
} 

Presenter—>View

public class WetherPresenter {
    IWetherModel mModel;
    IWetherView mView;

    ......
    public WetherPresenter(IWetherView mView) {
        this.mView = mView;
    }
    ......
}

7.Presenter与View的通信

Presenter—->Model

public class WetherPresenter {
    IWetherModel mModel;
    IWetherView mView;

    ......
    public WetherPresenter(IWetherView mView) {
        this.mView = mView;
        mModel =  new IWetherModelImpl(this);
    }
    ......
}

Model—->Presenter

public class IWetherImpl implements IWetherModel {
    WetherPresenter mPresenter;
    public IWetherImpl(WetherPresenter presenter) {
        this.mPresenter = presenter;
    }
    @Override
    public String getInfo() {
        return null;
    }

    @Override
    public void setInfo(String info) {

    }
}

完成这些后,就可以进行V–>P–>M–>P–>V 的过程

四.借鉴谷歌官方的写法

我借鉴的是谷歌MVP-Rxjava的写法,大部分和原写法相同,在某些地方进行了改进,谷歌官方的写法中,Fragment作为V,Activity只是作为将两者进行绑定的渠道,我在项目中,将Activity作为V。
谷歌官方MVP + Rxjava的讲解:Google官方MVP+Rxjava项目详解

在我的项目中的应用:以四六级查询为例

1.定义基础的P和V接口

public interface BasePresenter {

    //订阅
    void subscribe();

    //取消订阅
    void unSubscribe();

}
public interface BaseView<T> {
    void setPresenter(T presenter);

}

2.定义Contract接口

在Contract接口中设置该模块 V和P提供的接口

public interface ComputersGradeContract {

    interface View extends BaseView<Presenter> {
        void cgGetTimes(CgTimes cgTimes);  //展示时间

        void cgShowValidateCode(Bitmap bitmap); //展示验证码

        void cgShowGrade(CgQuery cgQuery); //展示成绩

        void cgFailure(String str); //请求失败
    }

    interface Presenter extends BasePresenter {
        void cgSetValidateCode(); //请求验证码

        void cgSetGrade(CgDemandDate cgDemandDate); //请求成绩
    }
}

3.定义协议类EducationDataSource

这个就是定义M的接口,里面写了M需要实现的接口。

public interface EducationDataSource {

    //计算机等级考试
    Observable<CgTimes> cgTimes();

    Observable<Bitmap> cgValidateCode();

    Observable<CgQuery> cgGrade(CgDemandDate cgDemandDate);
}

4.V的实现类 ComputersGradeActivity

public class ComputersGradeActivity extends BaseActivity implements ComputersGradeContract.View {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_computers_grade);

        initView();
        clickJudge();

        //创建一个P实例
        //参数1 M的实例
        //参数2 V的实例
        new ComputersGradePresenter(Injection.provideTasksRepository(getApplicationContext()), this);
    } 
    ...

    @Override
    public void onResume() {
        super.onResume();
        mPresenter.subscribe(); //P进行订阅
    }

    @Override
    public void onPause() {
        super.onPause();
        mPresenter.unSubscribe();//P取消订阅
    }


    @Override
    public void setPresenter(@NonNull ComputersGradeContract.Presenter presenter) {
        mPresenter = presenter; // v-->P
    }


    @Override //展示时间  提供给P调用的接口
    public void cgGetTimes(CgTimes cgTimes) {
        mDateSet = cgTimes.data;
        OptionsPickerView lessonDatePickerView = getDateOptionPickerView(cgTimes);
        mLlDate.setOnClickListener(view -> lessonDatePickerView.show());
    }


    @Override //展示验证码  提供给P调用的接口
    public void cgShowValidateCode(Bitmap bitmap) {
        mIvCode.setImageBitmap(bitmap);
    }


    @Override//展示成绩  提供给P调用的接口
    public void cgShowGrade(CgQuery cgQuery) {
        if(cgQuery.status == 500){
            Toast.makeText(Utils.getContext(), "信息有误", Toast.LENGTH_SHORT).show();
        }else if(cgQuery.data == null){
            Toast.makeText(Utils.getContext(), "验证码错误", Toast.LENGTH_SHORT).show();
            mPresenter.cgSetValidateCode();
        }else {
            mAnimatorSet.start();
            mTvGrade.setText(cgQuery.data.status);
            mTvCredential.setText(cgQuery.data.zkzh);
        }
    }

    @Override //请求失败
    public void cgFailure(String str) {
        Toast.makeText(Utils.getContext(), str, Toast.LENGTH_SHORT).show();

    }
}

Injection类


public class Injection {
    public static EducationRepository provideTasksRepository(@NonNull Context context) {

        return EducationRepository.getInstance(
                EducationRemoteDataSource.getInstance(),
                EducationLocalDataSource.getInstance(context));
    }

}

5. P的实现类 ComputersGradePresenter

public class ComputersGradePresenter implements ComputersGradeContract.Presenter {

    @NonNull
    private final ComputersGradeContract.View mView;  //V的实例
    @NonNull
    private final EducationRepository mEducationRepository; //M的实例

    @NonNull
    private CompositeDisposable mCompositeDisposable;

    private static final String TAG = "ComputersGradePresenter";
    public ComputersGradePresenter(@Nullable EducationRepository educationRepository,
                                   @NonNull ComputersGradeContract.View view) {

        //p和V绑定
        mView = view;
        //p和M绑定
        mEducationRepository = educationRepository;
        //V和p绑定
        mView.setPresenter(this);

        mCompositeDisposable = new CompositeDisposable();
    }


    //订阅
    @Override
    public void subscribe() {
        cgSetTimes(); //请求时间
        cgSetValidateCode(); //请求验证码
    }

    //取消订阅
    @Override
    public void unSubscribe() {
        mCompositeDisposable.clear();
    }


    //获取时间列表
    public void cgSetTimes() {   //使用RXjava对M发送回的事件进行处理
        mCompositeDisposable.add(mEducationRepository
                .cgTimes() //调用M的cgTimes方法 
                .subscribeOn(Schedulers.io()) //提供Scheduler用于Rxjava线程调度
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        // onNext
                        cgTimes-> {
                            if (cgTimes == null) {
                                mView.cgFailure("网络请求失败"); //调用页面出错
                            } else {
                                mView.cgGetTimes(cgTimes);
                            }
                        },
                        // onError
                        throwable -> mView.cgFailure("网络请求失败")));//调用页面出错
    }


    @Override  //获取验证码
    public void cgSetValidateCode() {

        mCompositeDisposable.add(mEducationRepository
                .cgValidateCode()
                .subscribeOn(Schedulers.io()) //提供Scheduler用于Rxjava线程调度
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        // onNext
                        bitmap-> {
                            if (bitmap == null) {
                                mView.cgFailure("网络请求失败1"); //调用页面出错
                            } else {
                                mView.cgShowValidateCode(bitmap);
                            }
                        },
                        // onError
                        throwable -> mView.cgFailure("网络请求失败2"))); //调用页面出错
    }

    @Override //获取成绩
    public void cgSetGrade(CgDemandDate cgDemandDate) {

        mCompositeDisposable.add(mEducationRepository
                .cgGrade(cgDemandDate)
                .subscribeOn(Schedulers.io()) //提供Scheduler用于Rxjava线程调度
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        // onNext
                        cgQuery-> {
                            if (cgQuery == null) {
                                mView.cgFailure("信息有误"); //调用页面出错
                            } else {
                                mView.cgShowGrade(cgQuery);
                            }
                        },
                        // onError
                        throwable -> mView.cgFailure("信息有误"))); //调用页面出错
    }
}

6. M的实现类

M的实现类有三个:EducationRepository,EducationRemoteDataSource代表网络数据,EducationLocalDataSource 代表本地数据,EducationRepository根据需求决定调用哪一个DataSource。
EducationRepository

ublic class EducationRepository implements EducationDataSource {
    @NonNull
    private final EducationDataSource mTasksRemoteDataSource;

    @NonNull
    private final EducationDataSource mTasksLocalDataSource;

    //单例模式
    private EducationRepository(@NonNull EducationDataSource tasksRemoteDataSource,
                            @NonNull EducationDataSource tasksLocalDataSource) {
        mTasksRemoteDataSource = tasksRemoteDataSource;
        mTasksLocalDataSource = tasksLocalDataSource;
    }

    @Nullable
    private static EducationRepository INSTANCE = null;
    public static EducationRepository getInstance(@NonNull EducationDataSource tasksRemoteDataSource,
                                              @NonNull EducationDataSource tasksLocalDataSource) {
        if (INSTANCE == null) {
            INSTANCE = new EducationRepository(tasksRemoteDataSource, tasksLocalDataSource);
        }
        return INSTANCE;
    }

    @Override
    public Observable<CgTimes> cgTimes() {
        return mTasksRemoteDataSource.cgTimes();
    }

    @Override
    public Observable<Bitmap> cgValidateCode() {
        return mTasksRemoteDataSource.cgValidateCode();
    }

    @Override
    public Observable<CgQuery>  cgGrade(CgDemandDate cgDemandDate) {
        return mTasksRemoteDataSource. cgGrade(cgDemandDate);
    }

}

EducationRemoteDataSource类

public class EducationRemoteDataSource implements EducationDataSource {
    private static EducationRemoteDataSource INSTANCE; //单例


    // Prevent direct instantiation.
    private EducationRemoteDataSource() {

    }

    public static EducationRemoteDataSource getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new EducationRemoteDataSource();
        }
        return INSTANCE;
    }

    @Override
    public Observable<CgTimes> cgTimes() {

        return  RetrofitFactory.INSTANCE.create(EducationApi.class)
                .cgGetTimes()
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .flatMap(new Function<CgTimes, ObservableSource<CgTimes>>() {//将请求的结果封装成一个新的事件
                    @Override
                    public ObservableSource<CgTimes> apply(CgTimes cgTimes) throws Exception {
                        return Observable.create(e -> e.onNext(cgTimes));
                    }
                });
    }


    @Override
    public Observable<Bitmap> cgValidateCode() {

        return RetrofitFactory.INSTANCE.create(EducationApi.class)
                .cgGetCode()
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .flatMap(new Function<ResponseBody, ObservableSource<Bitmap>>() { //将请求的结果封装成一个新的事件
                    @Override
                    public ObservableSource<Bitmap> apply(ResponseBody responseBody) throws Exception {

                        Bitmap bitmap = BitmapFactory.decodeStream(responseBody.byteStream());
                        return Observable.create(e -> e.onNext(bitmap));
                    }
                });

    }


    @Override
    public Observable<CgQuery> cgGrade(CgDemandDate cgDemandDate) {

        return RetrofitFactory.INSTANCE.create(EducationApi.class)
                .cgGetQuery(cgDemandDate.getDate(),cgDemandDate.getType(),cgDemandDate.getNum(),cgDemandDate.getName(),cgDemandDate.getCode())
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .flatMap(new Function<CgQuery, ObservableSource<CgQuery>>() {
                    @Override
                    public ObservableSource<CgQuery> apply(CgQuery cgGuery) throws Exception {
                        return Observable.create(e -> e.onNext(cgGuery));
                    }
                });
    }

在我的项目中,这个模块没有用的EducationLocalDataSource,所以基本它对应的方法返回的都是空值。

猜你喜欢

转载自blog.csdn.net/qq_38499859/article/details/81610874
今日推荐