本Demo使用 Okhttp3、Retrofit2、Rxjava2 ,使用AutoDispose解决RxJava内存泄漏
Github:
https://github.com/RookieExaminer/MvpDemo
什么是MVP,为什么要用MVP?
网上介绍MVP的很多,百度一下你就知道,至于为什么要用MVP,当然是由于它的优势了:
1.代码简洁
此处的简洁是逻辑的简洁,而不是代码本身 举个栗子

image.png
比如购物车界面,有很多请求网络的地方:获取购物车商品列表、购物车商品的删除、购物车商品的购买等等, 这么多网络请求,如果都写在一个Activity,而且还有大量逻辑判断,那这个Activity的行数~ 看着就让人头痛, 即便写了注释,维护起来也是比较麻烦的
2.降低耦合,方便维护
MVP的使用,使Activity中的网络请求剥离出来 成为model、presenter,model只负责网络的请求、pesenter负责处理请求网络后的数据处理:加载中 成功 or 失败 取消加载;最后View进行界面的展示

image.png

image.png
Start 看图:

image.png
嗯哼? 不是 Model、Presenter、View这三个 么,怎么又多出来个Contract,这又是什么鬼?
这就涉及到MVP的缺点了,正所谓,金无足赤,人无完人,MVP既然有优点当然也有它的缺点了
MVP在实现代码简洁的同时,额外增加了大量的接口、类,不方便进行管理,于是Contract就登场了。
Contract 百度翻译 : 合同;契约;协议
Contract 如其名,是一个契约,将Model、View、Presenter 进行约束管理,方便后期类的查找、维护。
下面演示下登陆的MVP实现方式:
(示例代码由开发项目中剥离到Demo中,登陆接口使用的是玩安卓的登陆API:http://www.wanandroid.com/blog/show/2)
首先,创建一个登陆的Contract:public interface MainContract { interface Model { } interface View extends BaseView { } interface Presenter { }
}
其次创建Presenter、Model、View 对应Contract中的接口;public class MainPresenter implements MainContract.Model{}public class MainModel implements MainContract.Presenter{}public class MainActivity implements MainContract.View {}完整的Contract:
public interface MainContract { interface Model {
Flowable<BaseObjectBean<LoginBean>> login(String username, String password);
} interface View extends BaseView { @Override
void showLoading(); @Override
void hideLoading(); @Override
void onError(Throwable throwable); void onSuccess(BaseObjectBean<LoginBean> bean);
} interface Presenter { /**
* 登陆
*
* @param username
* @param password
*/
void login(String username, String password);
}
}在MainContract 中
Model接口 创建对应的联网请求的方法,将Presenter提交的字段放到联网请求中,发送给服务器
View 接口 创建在界面上显示加载中、取消加载以及登陆成功、失败的方法
Presenter 接口 创建 登陆的方法,以及需要提交的字段 (username、password)
MainModel的完整代码:
public class MainModel implements MainContract.Model { @Override
public Flowable<BaseObjectBean<LoginBean>> login(String username, String password) { return RetrofitClient.getInstance().getApi().login(username,password);
}
}Model类实现MainContract.Model 接口中的 login(String username, String password)方法,将username、password放在联网请求中,进行请求服务器。
MainView 的完整代码:
public class MainActivity extends BaseMvpActivity<MainPresenter> implements MainContract.View { @BindView(R.id.et_username_login)
TextInputEditText etUsernameLogin; @BindView(R.id.et_password_login)
TextInputEditText etPasswordLogin; @Override
public int getLayoutId() { return R.layout.activity_main;
} @Override
public void initView() {
mPresenter = new MainPresenter();
mPresenter.attachView(this);
} /**
* @return 帐号
*/
private String getUsername() { return etUsernameLogin.getText().toString().trim();
} /**
* @return 密码
*/
private String getPassword() { return etPasswordLogin.getText().toString().trim();
} @Override
public void onSuccess(BaseObjectBean bean) {
Toast.makeText(this, bean.getErrorMsg(), Toast.LENGTH_SHORT).show();
} @Override
public void showLoading() {
ProgressDialog.getInstance().show(this);
} @Override
public void hideLoading() {
ProgressDialog.getInstance().dismiss();
} @Override
public void onError(Throwable throwable) {
} @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // TODO: add setContentView(...) invocation
ButterKnife.bind(this);
} @OnClick(R.id.btn_signin_login) public void onViewClicked() { if (getUsername().isEmpty() || getPassword().isEmpty()) {
Toast.makeText(this, "帐号密码不能为空", Toast.LENGTH_SHORT).show(); return;
}
mPresenter.login(getUsername(), getPassword());
}
}MainActivity 中实现 MainContract.View中的方法 ,在实现的方法中,进行进度条加载、和登陆成功or失败的UI的展示:
@Override void showLoading(); @Override void hideLoading(); @Override void onError(Throwable throwable); void onSuccess(BaseObjectBean<LoginBean> bean);
MainPresenter 的完整代码:
public class MainPresenter extends BasePresenter<MainContract.View> implements MainContract.Presenter { private MainContract.Model model; public MainPresenter() {
model = new MainModel();
} @Override
public void login(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(new Consumer<BaseObjectBean<LoginBean>>() { @Override
public void accept(BaseObjectBean<LoginBean> bean) throws Exception {
mView.onSuccess(bean);
mView.hideLoading();
}
}, new Consumer<Throwable>() { @Override
public void accept(Throwable throwable) throws Exception {
mView.onError(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类:
public interface BaseView { /**
* 显示加载中
*/
void showLoading(); /**
* 隐藏加载
*/
void hideLoading(); /**
* 数据获取失败
* @param throwable
*/
void onError(Throwable throwable); /**
* 绑定Android生命周期 防止RxJava内存泄漏
*
* @param <T>
* @return
*/
<T> AutoDisposeConverter<T> bindAutoDispose();
}至于为什么不把onSuccess()方法也封装,是因为请求网络,服务器返回的值是不一样的,在Contract > View接口中根据bean类设置onSuccess()
BasePresenter类:
public class BasePresenter<V extends BaseView> { protected V mView; /**
* 绑定view,一般在初始化中调用该方法
*
* @param view view
*/
public void attachView(V view) { this.mView = view;
} /**
* 解除绑定view,一般在onDestroy中调用
*/
public void detachView() { this.mView = null;
} /**
* View是否绑定
*
* @return
*/
public boolean isViewAttached() { return mView != 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


随时随地看视频
热门评论
-
hyk2019-04-24 0
查看全部评论.as(mView.<BaseObjectBean<LoginBean>>bindAutoDispose())是什么意思?能解释一下吗?