本Demo使用 Okhttp3、Retrofit2、Rxjava2 ,使用AutoDispose解决RxJava内存泄漏
Github:
https://github.com/RookieExaminer/MvpDemo
什么是 MVP,为什么要用MVP?
网上介绍MVP的很多,百度一下你就知道,至于为什么要用MVP,当然是由于它的优势了:
1、代码简洁
此处的简洁是逻辑的简洁,而不是代码本身 举个栗子
比如购物车界面,有很多请求网络的地方:获取购物车商品列表、购物车商品的删除、购物车商品的购买等等, 这么多网络请求,如果都写在一个 Activity,而且还有大量逻辑判断,那这个 Activity的行数~ 看着就让人头痛, 即便写了注释,维护起来也是比较麻烦的
2.降低耦合,方便维护
MVP的使用,使Activity中的网络请求剥离出来 成为model、presenter,model只负责网络的请求、pesenter负责处理请求网络后的数据处理:加载中 成功 or 失败 取消加载;最后View进行界面的展示
Start 看图:
嗯哼? 不是 Model、Presenter、View这三个 么,怎么又多出来个Contract,这又是什么鬼?
这就涉及到MVP的缺点了,正所谓,金无足赤,人无完人,MVP既然有优点当然也有它的缺点了
MVP在实现代码简洁的同时,额外增加了大量的接口、类,不方便进行管理,于是Contract 就登场了。
Contract 百度翻译 : 合同;契约;协议
Contract 如其名,是一个契约,将 Model、View、Presenter 进行约束管理,方便后期类的查找、维护。
下面演示下登陆的MVP实现方式
(示例代码由开发项目中剥离到Demo中,登陆接口使用的是玩安卓的登陆API:http://www.wanandroid.com/blog/show/2)
首先,创建一个登陆的Contract:
publicinterfaceMainContract{ interfaceModel{ } interfaceViewextendsBaseView{ } interfacePresenter{ } } 其次创建 Presenter、Model、View 对应 Contract 中的接口; publicclassMainPresenterimplementsMainContract.Model{} publicclassMainModelimplementsMainContract.Presenter{} publicclassMainActivityimplementsMainContract.View{} 完整的 Contract: publicinterfaceMainContract{ interfaceModel{ Flowable<BaseObjectBean<LoginBean>> login(String username, String password); } interfaceViewextendsBaseView{ @Override voidshowLoading(); @Override voidhideLoading(); @Override void(Throwable throwable); voidonSuccess(BaseObjectBean<LoginBean> bean); } interfacePresenter{ /** * 登陆 * * @paramusername * @parampassword */ voidlogin(String username, String password); } }
在 MainContract 中
MainModel的完整代码:
publicclassMainModelimplementsMainContract.Model{ @Override publicFlowable<BaseObjectBean<LoginBean>> login(String username, String password) { returnRetrofitClient.getInstance().getApi().login(username,password); } } Model 类实现 MainContract.Model 接口中的 login(String username, String password)方法,将 username、password 放在联网请求中,进行请求服务器。 MainView 的完整代码: publicclassMainActivityextendsBaseMvpActivity<MainPresenter> implementsMainContract.View{ @BindView(R.id.et_username_login) TextInputEditText etUsernameLogin; @BindView(R.id.et_password_login) TextInputEditText etPasswordLogin; @Override publicintgetLayoutId(){ returnR.layout.activity_main; } @Override publicvoidinitView(){ mPresenter = newMainPresenter(); mPresenter.attachView(this); } /** * @return帐号 */ privateString getUsername(){ returnetUsernameLogin.getText().toString().trim(); } /** * @return密码 */ privateString getPassword(){ returnetPasswordLogin.getText().toString().trim(); } @Override publicvoidonSuccess(BaseObjectBean bean){ Toast.makeText(this, bean.getErrorMsg(), Toast.LENGTH_SHORT).show(); } @Override publicvoidshowLoading(){ ProgressDialog.getInstance().show(this); } @Override publicvoidhideLoading(){ ProgressDialog.getInstance().dismiss(); } @Override publicvoid(Throwable throwable){ } @Override protectedvoidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); // TODO:add setContentView(...) invocation ButterKnife.bind(this); } @OnClick(R.id.btn_signin_login) publicvoidonViewClicked(){ if(getUsername().isEmpty() || getPassword().isEmpty()) { Toast.makeText(this, "帐号密码不能为空", Toast.LENGTH_SHORT).show(); return; } mPresenter.login(getUsername(), getPassword()); } } MainActivity 中实现 MainContract.View中的方法 ,在实现的方法中,进行进度条加载、和登陆成功or失败的UI的展示: @Override voidshowLoading(); @Override voidhideLoading(); @Override void(Throwable throwable); voidonSuccess(BaseObjectBean<LoginBean> bean);
MainPresenter 的完整代码:
publicclassMainPresenterextendsBasePresenter<MainContract.View> implementsMainContract.Presenter{ privateMainContract.Model model; publicMainPresenter(){ model = newMainModel(); } @Override publicvoidlogin(String username, String password){ if(!isViewAttached()) { return; } mView.showLoading(); model.login(username, password) .compose(RxScheduler.<BaseObjectBean<LoginBean>>Flo_io_main()) .as(mView.<BaseObjectBean<LoginBean>>bindAutoDispose()) .subscribe(newConsumer<BaseObjectBean<LoginBean>>() { @Override publicvoidaccept(BaseObjectBean<LoginBean> bean)throwsException { mView.onSuccess(bean); mView.hideLoading(); } }, newConsumer<Throwable>() { @Override publicvoidaccept(Throwable throwable)throwsException { mView.(throwable); mView.hideLoading(); } }); } }
MainPresenter 实现 MainContract.Presenter 接口中的 login(String username, String password) 方法
实例化Model,在 MainPresenter login(String username, String password)方法中,调用 model的网络请求,将 username、password 放在model 的 login() 方法中,进行请求服务器。
请求服务器前 使用 MainContract.View 中的 mView.showLoading()方法,进行显示加载中;在成功失败的回调中,使用对应的方法,以及取消加载。
其中BasePresenter、BaseView 是对Presenter以及View进行的封装
BaseView类:
publicinterfaceBaseView{ /** * 显示加载中 */ voidshowLoading(); /** * 隐藏加载 */ voidhideLoading(); /** * 数据获取失败 * @paramthrowable */ void(Throwable throwable); /** * 绑定Android生命周期 防止RxJava内存泄漏 * * @param<T> * @return */ <T> AutoDisposeConverter<T> bindAutoDispose(); }
至于为什么不把 onSuccess()方法也封装,是因为请求网络,服务器返回的值是不一样的,在 Contract > View 接口中根据 bean 类设置 onSuccess()
BasePresenter类:
publicclassBasePresenter<VextendsBaseView> { protectedV mView; /** * 绑定view,一般在初始化中调用该方法 * * @paramview view */ publicvoidattachView(V view){ this.mView = view; } /** * 解除绑定view,一般在onDestroy中调用 */ publicvoiddetachView(){ this.mView = null; } /** * View是否绑定 * * @return */ publicbooleanisViewAttached(){ returnmView != null; } }
时间有限,暂时就先这样,具体可下载 Demo查看 ↓
本Demo:https://github.com/RookieExaminer/MvpDemo MVP快速生成类的插件:https://github.com/githubwing/MVPHelper
参考:
Android MVP架构搭建:http://www.jcodecraeer.com/a/anzhuokaifa/2017/1020/8625.html?1508484926
Android架构中添加AutoDispose解决RxJava内存泄漏:https://www.jianshu.com/p/8490d9383ba5
按字母顺序浏览:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
→我们致力于为广大网民解决所遇到的各种电脑技术问题 如果您认为本词条还有待完善,请 编辑词条