MVP+Retrofit+RxJava的Demo獲取豆瓣電影信息
??github地址:https://github.com/Veken/MVPDemo/tree/master
??想必大家都一樣拇勃,剛開(kāi)始擼android的時(shí)候懈贺,都是用的MVC模式,主要都是因?yàn)轫?xiàng)目不是很大左电,一兩個(gè)人做牌废,也沒(méi)考慮那么多咽白,所有的業(yè)務(wù)邏輯,網(wǎng)絡(luò)請(qǐng)求代碼等等都是直接在Activity和Fragment里面堆鸟缕,往往弄的一個(gè)頁(yè)面要寫(xiě)幾百上千行晶框,考慮到以后的維護(hù)成本,以及大項(xiàng)目的業(yè)務(wù)拓展叁扫,本著學(xué)習(xí)使人進(jìn)步的歷史名言三妈,趕緊學(xué)習(xí)MVP模式。
??剛開(kāi)始接觸莫绣,不太熟練畴蒲,也不太懂,就擼一個(gè)簡(jiǎn)單的RxJava2+Retrofit+Mvp的小demo(想要學(xué)習(xí)RxJava2的同學(xué)可以點(diǎn)擊給初學(xué)者的RxJava2.0教程)对室,主要內(nèi)容就是獲取豆瓣的電影信息模燥,loading的時(shí)候咖祭,給一個(gè)ProgressDialog,顯示加載的進(jìn)度∧杪睿現(xiàn)在開(kāi)始上代碼:
??BaseView中封裝了一些頁(yè)面加載的狀態(tài)么翰,比如加載成功,失敗辽旋,沒(méi)有網(wǎng)絡(luò)浩嫌,等等。還綁定了一個(gè)Rxjava的生命周期LifecycleTransformer(用來(lái)解決Disposable或者是CompositeDisposable切斷網(wǎng)絡(luò)的聯(lián)系)补胚。
public interface BaseContract {
interface BasePresenter<T extends BaseContract.BaseView> {
void attachView(T view);
void detachView();
}
interface BaseView{
//顯示進(jìn)度中
void showLoading();
//顯示請(qǐng)求成功
void showSuccess();
//失敗重試
void showFaild();
//顯示當(dāng)前網(wǎng)絡(luò)不可用
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;
//進(jìn)行綁定
public void attachView(T view) {
this.mView = view;
}
//解綁
@Override
public void detachView() {
if (mView != null) {
mView = null;
}
}
}
??BaseActivity中最主要的是如果要實(shí)現(xiàn)綁定RxJava的LifecycleTransformer溶其,就得繼承RxAppCompatActivity骚腥,然后還要導(dǎo)包
compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0'
compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
??把一些加載網(wǎng)絡(luò)的狀態(tài)統(tǒng)一封裝在這,方便于統(tǒng)一管理瓶逃,在onCreate()的時(shí)候束铭,綁定View,onDestroy()的時(shí)候解綁View厢绝,避免造成內(nèi)存泄漏契沫。
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);
}
//沒(méi)有網(wǎng)絡(luò)
if(!NetworkUtil.isNetworkConnected(this)){
showNoNet();
return;
}
//加載數(shù)據(jù)
initData();
dialog = DialogLoading.getLoadingDialog(this);
}
/**
* 布局資源
* @return
*/
protected abstract int layoutId();
/**
* 初始化數(shù)據(jù)
*/
protected abstract void initData();
/**
* 創(chuàng)建當(dāng)前presenter
* @return
*/
protected abstract T createPresenter();
/**
* 沒(méi)有網(wǎng)絡(luò)
*/
@Override
public void showNoNet() {
dismissDialog();
ToastUtil.toastLong("沒(méi)有網(wǎng)絡(luò)訪問(wèn)");
}
/**
* 重新加載
*/
@Override
public void onRetry() {
initData();
}
@Override
public void showSuccess() {
ToastUtil.toastLong("加載成功");
dismissDialog();
}
/**
* 加載進(jìn)度消失
*/
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的生命周期,類(lèi)似于以前的Disposable或者是CompositeDisposable切斷聯(lián)系,避免造成內(nèi)存泄漏
*
* @param <T>
* @return
*/
@Override
public <T> LifecycleTransformer<T> bindToLife() {
return this.bindToLifecycle();
}
@Override
protected void onDestroy() {
super.onDestroy();
//避免內(nèi)存泄漏
if (presenter != null) {
presenter.detachView();
}
ButterKnife.unbind(this);
}
}
??具體的頁(yè)面實(shí)現(xiàn):
public interface HotMovieContract {
interface View extends BaseContract.BaseView{
//得到數(shù)據(jù)
void loadData(HotMovieBean hotMovieBeen);
}
interface Presenter extends BaseContract.BasePresenter<View>{
//請(qǐng)求網(wǎng)絡(luò)昔汉,如果需要請(qǐng)求參數(shù)埠褪,可以在里面添加參數(shù)
void getData();
}
}
??獲取數(shù)據(jù):
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()) //轉(zhuǎn)換線程
.compose(mView.<HotMovieBean>bindToLife()) //綁定生命周期
.subscribe(new BaseObserver<HotMovieBean>() {
@Override
public void onSucess(HotMovieBean hotMovieBean) {
mView.loadData(hotMovieBean);
//如果不想要加載成功后的顯示,比如彈一個(gè)toast挤庇,可以取消
mView.showSuccess();
}
@Override
public void onFail(Throwable e) {
mView.showFaild();
}
});
}
}
??在Activity中調(diào)用就很簡(jiǎn)單了钞速,繼承BaseActivity,實(shí)現(xiàn)該頁(yè)面的View邏輯,初始化Presenter嫡秕,獲取數(shù)據(jù)渴语,得到數(shù)據(jù)。
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模式第一次嘗試昆咽,寫(xiě)的不好驾凶,請(qǐng)見(jiàn)諒,還得多跟項(xiàng)目實(shí)戰(zhàn)結(jié)合掷酗,才能體會(huì)到它功能強(qiáng)大的地方调违。但是確實(shí)解耦了,在Activity中的代碼精簡(jiǎn)了很多泻轰,維護(hù)和拓展性也更高技肩。Fragment中使用也是類(lèi)似,封裝BaseFragment浮声,和BaseActivity差不多虚婿。
感謝:
?? 萬(wàn)能的RecyclerView適配器