当前位置: 首页 > 科技观察

Android中的MVP模式(附实例)

时间:2023-03-12 11:06:10 科技观察

最近在利用业余时间研究各种网络开源项目,也在搭建一个android开源框架,希望能做一个知识总结。这里我们用一个简单的应用来说明MVP。后面还有很多github源码,都是特别经典的例子,可以借鉴。(1).MVP模式介绍相信大家对MVC都不陌生:M-Model-model,V-View-view,C-Controller-controller,MVP是MVC的进化版,那么类似的MVP对应的意思是:M-Model-model,V-View-view,P-Presenter-presenter。从MVC和MVP的结合来看,Controller/Presenter在MVC/MVP中都扮演着逻辑控制处理的角色,起到控制各种业务流程的作用。MVP和MVC最不同的一点就是M和V没有直接关系,Model和View没有直接关系。两者之间有一个Presenter层,负责规范View和Model之间的间接交互。.Android中很重要的一点就是UI的操作基本都需要异步进行,也就是只能在MainThread中操作UI,所以View和Model分离是合理的。另外,Presenter、View、Model之间的交互使用接口来定义交互操作,可以进一步实现松耦合,通过接口可以更方便的进行单元测试。于是就有了这张图(MVP和MVC的对比)。其实MVP和MVC最明显的区别就是在MVC中允许Model和View进行交互,而在MVP中很明显Model和View的交互是由Presenter完成的。还有一点就是Presenter和View的交互是通过界面进行的(会在代码中体现)。(2).MVP模式的应用2.1Model层描述及具体代码提供了我们要在view层展示的数据以及具体登录业务逻辑处理的实现,packagecom.nsu.edu.androidmvpdemo.login;/***CreatedbyAnthonyon2016/2/15.*ClassNote:模拟登录操作的接口,实现类为LoginModelImpl。相当于MVP模式下的Model层*/publicinterfaceLoginModel{voidlogin(Stringusername,Stringpassword,OnLoginFinishedListenerlistener);}packagecom.nsu.edu.androidmvpdemo.login;importandroid.os.Handler;importandroid.text.TextUtils;/***CreatedbyAnthonyon2016/2/15.*ClassNote:延迟模拟登录(2s),如果用户名或密码为空,则登录失败,否则登录成功*/publicclassLoginModelImplimplementsLoginModel{@Overridepublicvoidlogin(finalStringusername,finalStringpassword,finalOnLoginFinishedListenerlistener){newHandler().postDelayed(newRunnable(){@Overridepublicvoidrun(){booleanerror=false;if(TextUtils.isEmpty(username)){listener.onUsernameError();//模型层内部回调listenererror=true;}if(TextUtils.isEmpty(password)){listener.onPasswordError();error=true;}if(!error){listener.onSuccess();}}},2000);}}2.2视图层描述和具体代码负责显示数据,提供友好的界面并与我们互动呃。MVP下的Activity、Fragment、View子类都体现在这一层。Activity一般会做一些加载UI视图,设置监听,然后交给Presenter处理的工作,所以它也需要持有对应Presenter的引用。这一层需要做的操作是每次有相应的交互时调用presenter的相关方法。(比如点击按钮)packagecom.nsu.edu.androidmvpdemo.login;/***CreatedbyAnthonyon2016/2/15.*ClassNote:登录View的接口,实现类是登录activity*/publicinterfaceLoginView{voidshowProgress();voidhideProgress();voidsetUsernameError();voidsetPasswordError();voidnavigateToHome();}packagecom.nsu.edu.androidmvpdemo.login;importandroid.app.Activity;importandroid.content.Intent;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.EditText;importandroid.widget.ProgressBar;importandroid.widget.Toast;importcom.nsu.edu.androidmvpdemo.R;/***CreatedbyAnthonyon2016/2/15.*ClassNote:在MVP模式下,View层对应一个activity,这里是登陆的activity*/publicclassLoginActivityextendsActivityimplementsLoginView,View.OnClickListener{privateProgressBarprogressBar;privateEditTextusername;privateEditTextpassword;privateLoginPresenterpresenter;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layoutprogress.activity_Barlogin);(进度条)findViewById(R.id.progress);username=(EditText)findViewById(R.id.username);password=(EditText)findViewById(R.id.password);findViewById(R.id.button).setOnClickListener(this);presenter=newLoginPresenterImpl(this);}@OverrideprotectedvoidonDestroy(){presenter.onDestroy();super.onDestroy();}@OverridepublicvoidshowProgress(){progressBar.setVisibility(View.VISIBLE);}@OverridepublicvoidhideProgress(){progressBar.setVisibility(View.GONE);}@OverridepublicvoidsetUsernameError(){username.setError(getString(R.string.username_error));}@OverridepublicvoidsetPasswordError(){password.setError(getString(R.string.password_error));}@OverridepublicvoidnavigateToHome(){//TODOstartActivity(newIntent(this,MainActivity.class));Toast.makeText(this,"loginsuccess",Toast.LENGTH_SHORT).show();//finish();}@OverridepublicvoidonClick(Viewv){presenter.validateCredentials(username.getText().toString(),password.getText().toString());}}2.3presenter层描述和具体代码Presenter扮演着view和model中间层的作用是获取模型层的数据,构建视图层;也可以接收视图层UI上的反馈命令,将处理逻辑分发到模型层进行业务操作。也可以决定View层的各种操作。packagecom.nsu.edu.androidmvpdemo.login;/***CreatedbyAnthonyon2016/2/15.*ClassNote:登录Presenter的接口,实现类为LoginPresenterImpl,完成登录验证并销毁当前视图*/publicinterfaceLoginPresenter{voidvalidateCredentials(Stringusername,Stringpassword);voidonDestroy();}packagecom.nsu.edu.androidmvpdemo.login;/***CreatedbyAnthonyon2016/2/15.*ClassNote:*1完成presenter的实现。这主要是Model层和View层的交互和操作。*2presenter中还有一个OnLoginFinishedListener,*在Presenter层实现,回调Model层改变View层的状态,*确保Model层不直接操作View层。如果这个接口没有在LoginPresenterImpl中实现,*LoginPresenterImpl只有View和Model的引用,那么Model怎么把结果告诉View呢?*/publicclassLoginPresenterImplementsLoginPresenter,OnLoginFinishedListener{privateLoginViewloginView;privateLoginModelloginModel;publicLoginPresenterImpl(LoginViewloginView){this.loginView=loginView;this.loginModel=newLoginModelImpl();}@OverridepublicvoidvalidateCredentials(Stringusername,Stringpassword){if(loginView!=null){loginView);}loginModel.login(username,password,this);}@OverridepublicvoidonDestroy(){loginView=null;}@OverridepublicvoidonUsernameError(){if(loginView!=null){loginView.setUsernameError();loginView.hideProgress();}}@OverridepublicvoidonPasswordError(){if(loginView!=null){loginView.setPasswordError();loginView.hideProgress();}}@OverridepublicvoidonSuccess(){if(loginView!=null){loginView.navigateToHome();}}}2.4登录回调接口包com.nsu.edu.androidmvpdemo.login;/***CreatedbyAnthonyon2016/2/15.*ClassNote:登录事件监听*/publicinterfaceOnLoginFinishedListener{voidonUsernameError();voidonPasswordError();voidonSuccess();}demo的代码流程:(请参考下面的类图)1Activity做了一些UI初始化,需要实例化对应的LoginPresenter的引用,实现的接口LoginView,监听界面action2登录按钮按下后,接收到登录事件,在onClick中接收到后,通过LoginPresenter引用传递给LoginPresenter处理。LoginPresenter收到登录逻辑,知道是时候登录了。3然后LoginPresenter显示一个进度条,并将逻辑交给我们的Model处理,就是里面的LoginModel,(LoginModel的实现类LoginModelImpl),以及OnLoginFinishedListener,这是LoginPresenter本身,将传递给我们的模型(LoginModel)。4LoginModel处理完逻辑后,通过OnLoginFinishedListener回调将结果通知给LoginPresenter5。然后LoginPresenter将结果返回给视图层的Activity。***activity的展示结果请参考这个类图:本项目类图(三)注:3.1Presenter还包含有一个OnLoginFinishedListener,在Presenter层实现,回调到Model层,改变View层的状态,保证Model层不直接操作View层。3.2在一个好的架构中,模型层可能只是领域层和业务逻辑层的入口。如果我们参考网上流行的UncleBobcleanarchitecture模型层,模型层可能是一个实现业务用例的交互器。后续文章中应该会涉及到这个问题,目前能力有限。这里暂且说明一下(4)MVP经典参考资料,直接参考文章,mvp模式的学习资料很多:android架构合集(请关注github,会持续更新)androidmvpgithub地址(这篇博客就是参考这个项目进行解释。这个项目也很简单,分为login和main两个模块,一共十个类,思路很清晰。正在学习的朋友可以直接clone查看源码。)androidmvp的src代码分为两个模块,login和main。为了操作简单,只增加了登录模块。本项目github地址:https://github.com/CameloeAnthony/AndroidMVPDemo