Android 谷歌官方MVP模式解读

一. 目录

      • Android 谷歌官方MVP模式解读
      • 一. 目录
      • 二.MVP的含义
        • 1.MVC模式
        • 2.MVP
      • 三.原来的写法
        • 1. 定义View接口,里面供提供p层抽象方法
        • 2. Activity或者Fragemt实现View接口
        • 3. Model层的接口定义,里面供提供p层抽象方法
        • 4. Model层实现
        • 5.Presenter代码及实现
        • 6.Presenter与View的通信
        • 7.Presenter与View的通信
      • 四.借鉴谷歌官方的写法
        • 1.定义基础的P和V接口
        • 2.定义Contract接口
        • 3.定义协议类EducationDataSource
        • 4.V的实现类 ComputersGradeActivity
        • 5. P的实现类 ComputersGradePresenter
        • 6. M的实现类

二.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 {    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();    Observable cgValidateCode();    Observable 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() {        return mTasksRemoteDataSource.cgTimes();    }    @Override    public Observable cgValidateCode() {        return mTasksRemoteDataSource.cgValidateCode();    }    @Override    public Observable  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() {        return  RetrofitFactory.INSTANCE.create(EducationApi.class)                .cgGetTimes()                .subscribeOn(Schedulers.io())                .observeOn(Schedulers.io())                .flatMap(new Function>() {//将请求的结果封装成一个新的事件                    @Override                    public ObservableSource apply(CgTimes cgTimes) throws Exception {                        return Observable.create(e -> e.onNext(cgTimes));                    }                });    }    @Override    public Observable cgValidateCode() {        return RetrofitFactory.INSTANCE.create(EducationApi.class)                .cgGetCode()                .subscribeOn(Schedulers.io())                .observeOn(Schedulers.io())                .flatMap(new Function>() { //将请求的结果封装成一个新的事件                    @Override                    public ObservableSource apply(ResponseBody responseBody) throws Exception {                        Bitmap bitmap = BitmapFactory.decodeStream(responseBody.byteStream());                        return Observable.create(e -> e.onNext(bitmap));                    }                });    }    @Override    public Observable 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>() {                    @Override                    public ObservableSource apply(CgQuery cgGuery) throws Exception {                        return Observable.create(e -> e.onNext(cgGuery));                    }                });    }

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

更多相关文章

  1. android2.3 api demo 学习系列(1)--apidemo主列表的实现
  2. Android(安卓)显示系统键盘搜索按键,实现搜索功能
  3. 写给初学者Android(安卓)AIDL必看内容
  4. Android(安卓)使用Parcelable传递对象
  5. 【Android(安卓)Demo】通过WebService获取今日天气情况
  6. Android(安卓)下使用 JSON 实现 HTTP 请求,外加几个示例!
  7. android Activity实现从底部弹出或滑出选择菜单或窗口
  8. DIY新浪微博Android手机客户端(一)(二)(三)完
  9. 浅谈Java中Collections.sort对List排序的两种方法

随机推荐

  1. Android——PullToRefresh自动刷新
  2. android下hci log
  3. Android之MVVM架构指南(五):ViewModel
  4. JWT在Java和Android中的使用
  5. android中OkHttp的导入和get、post请求的
  6. react-native启动android service bug解
  7. 属性动画(Property Animation)
  8. Android加载Class的思考
  9. Android(安卓)Studio上使用OpenCV-androi
  10. android ndk的使用