欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android MVP应用

程序员文章站 2022-05-12 20:25:39
...

Android 谷歌官方MVP模式解读

一. 目录

二.MVP的含义

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

1.MVC模式

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

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

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

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应用
Android MVP应用

在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,所以基本它对应的方法返回的都是空值。

相关标签: android MVp