MVP+Retrofit+RxJava的Demo获取豆瓣电影信息
github地址:https://github.com/Veken/MVPDemo/tree/master
想必大家都一样,刚开始撸android的时候,都是用的MVC模式,主要都是因为项目不是很大,一两个人做,也没考虑那么多,所有的业务逻辑,网络请求代码等等都是直接在Activity和Fragment里面堆,往往弄的一个页面要写几百上千行,考虑到以后的维护成本,以及大项目的业务拓展,本着学习使人进步的历史名言,赶紧学习MVP模式。
刚开始接触,不太熟练,也不太懂,就撸一个简单的RxJava2+Retrofit+Mvp的小demo(想要学习RxJava2的同学可以点击给初学者的RxJava2.0教程),主要内容就是获取豆瓣的电影信息,loading的时候,给一个ProgressDialog,显示加载的进度。现在开始上代码:
BaseView中封装了一些页面加载的状态,比如加载成功,失败,没有网络,等等。还绑定了一个Rxjava的生命周期LifecycleTransformer(用来解决Disposable或者是CompositeDisposable切断网络的联系)。
public interface BaseContract {
interface BasePresenter<T extends BaseContract.BaseView> {
void attachView(T view);
void detachView();
}
interface BaseView{
//显示进度中
void showLoading();
//显示请求成功
void showSuccess();
//失败重试
void showFaild();
//显示当前网络不可用
void showNoNet();
//重试
void onRetry();
/**
* 绑定生命周期
*
* @param <T>
* @return
*/
<T> LifecycleTransformer<T> bindToLife();
}
BasePresenter中绑定View,解绑View。
public class BasePresenter<T extends BaseContract.BaseView> implements BaseContract.BasePresenter<T> {
//1.View层的引用
protected T mView;
//进行绑定
public void attachView(T view) {
this.mView = view;
}
//解绑
@Override
public void detachView() {
if (mView != null) {
mView = null;
}
}
}
BaseActivity中最主要的是如果要实现绑定RxJava的LifecycleTransformer,就得继承RxAppCompatActivity,然后还要导包
compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0'
compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
把一些加载网络的状态统一封装在这,方便于统一管理,在onCreate()的时候,绑定View,onDestroy()的时候解绑View,避免造成内存泄漏。
public abstract class BaseActivity<T extends BaseContract.BasePresenter> extends RxAppCompatActivity implements BaseContract.BaseView {
//表示层的引用
@Nullable
protected T presenter;
protected Dialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layoutId());
ButterKnife.bind(this);
presenter = createPresenter();
if (presenter != null) {
presenter.attachView(this);
}
//没有网络
if(!NetworkUtil.isNetworkConnected(this)){
showNoNet();
return;
}
//加载数据
initData();
dialog = DialogLoading.getLoadingDialog(this);
}
/**
* 布局资源
* @return
*/
protected abstract int layoutId();
/**
* 初始化数据
*/
protected abstract void initData();
/**
* 创建当前presenter
* @return
*/
protected abstract T createPresenter();
/**
* 没有网络
*/
@Override
public void showNoNet() {
dismissDialog();
ToastUtil.toastLong("没有网络访问");
}
/**
* 重新加载
*/
@Override
public void onRetry() {
initData();
}
@Override
public void showSuccess() {
ToastUtil.toastLong("加载成功");
dismissDialog();
}
/**
* 加载进度消失
*/
private void dismissDialog(){
if (dialog != null) {
dialog.dismiss();
}
}
/**
* 加载失败
*/
@Override
public void showFaild() {
dismissDialog();
ToastUtil.toastLong("加载失败");
}
@Override
public void showLoading() {
if (dialog != null) {
dialog.show();
}
}
/**
* 绑定RxJava的生命周期,类似于以前的Disposable或者是CompositeDisposable切断联系,避免造成内存泄漏
*
* @param <T>
* @return
*/
@Override
public <T> LifecycleTransformer<T> bindToLife() {
return this.bindToLifecycle();
}
@Override
protected void onDestroy() {
super.onDestroy();
//避免内存泄漏
if (presenter != null) {
presenter.detachView();
}
ButterKnife.unbind(this);
}
}
具体的页面实现:
public interface HotMovieContract {
interface View extends BaseContract.BaseView{
//得到数据
void loadData(HotMovieBean hotMovieBeen);
}
interface Presenter extends BaseContract.BasePresenter<View>{
//请求网络,如果需要请求参数,可以在里面添加参数
void getData();
}
}
获取数据:
public class HotMoviePresenter extends BasePresenter<HotMovieContract.View> implements HotMovieContract.Presenter {
HotMovieService hotMovieService;
@Override
public void getData() {
if (hotMovieService == null) {
hotMovieService = RetrofitHandle.getInstance().retrofit.create(HotMovieService.class);
}
hotMovieService.fetchMovieTop250(0, 30)
.compose(RxSchedulers.<HotMovieBean>applySchedulers()) //转换线程
.compose(mView.<HotMovieBean>bindToLife()) //绑定生命周期
.subscribe(new BaseObserver<HotMovieBean>() {
@Override
public void onSucess(HotMovieBean hotMovieBean) {
mView.loadData(hotMovieBean);
//如果不想要加载成功后的显示,比如弹一个toast,可以取消
mView.showSuccess();
}
@Override
public void onFail(Throwable e) {
mView.showFaild();
}
});
}
}
在Activity中调用就很简单了,继承BaseActivity,实现该页面的View逻辑,初始化Presenter,获取数据,得到数据。
public class MainActivity extends BaseActivity<HotMoviePresenter> implements HotMovieContract.View {
@Bind(R.id.recycler_view)
RecyclerView recyclerView;
@Override
protected int layoutId() {
return R.layout.activity_main;
}
@Override
protected void initData() {
presenter.getData();
}
/**
* 初始化Presenter
* @return
*/
@Override
protected HotMoviePresenter createPresenter() {
return new HotMoviePresenter();
}
@Override
public void loadData(HotMovieBean hotMovieBeen) {
List<HotMovieBean.SubjectsBean> subjects = hotMovieBeen.getSubjects();
CommonAdapter adapter = new CommonAdapter(subjects);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
ToastUtil.toastShort(position + "");
}
});
}
}
MVP模式第一次尝试,写的不好,请见谅,还得多跟项目实战结合,才能体会到它功能强大的地方。但是确实解耦了,在Activity中的代码精简了很多,维护和拓展性也更高。Fragment中使用也是类似,封装BaseFragment,和BaseActivity差不多。
感谢:
万能的RecyclerView适配器