上一篇中簡單介紹了mvp的概念和retrofit的基本使用,本篇主要是將rxjava和retrofit結(jié)合起來使用,并搭建mvp+rxajva+retrofit的demo;沒有rxjava和retrofit基礎(chǔ)的,建議先去看上一篇:
Android 搭建MVP+Retrofit+RxJava網(wǎng)絡(luò)請求框架(一)
下面我們來看一下RxJava和retrofit的結(jié)合使用,為了使Rxjava與retrofit結(jié)合,我們需要在Retrofit對象建立的時候添加一句代碼:
addCallAdapterFactory(RxJava2CallAdapterFactory.create())
當然你還需要在build.gradle文件中添加如下依賴:
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
本篇中所用的是rxjava2,完整的代碼如下:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.douban.com/v2/")
.addConverterFactory(GsonConverterFactory.create(new
GsonBuilder().create()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//支持RxJava
.build();
然后我們還需要修改RetrofitService 中的代碼:
public interface RetrofitService {
@GET("book/search")
Observable<Book> getSearchBook(@Query("q") String name,
@Query("tag") String tag, @Query("start") int start,
@Query("count") int count);
可以看到,在原來的RetrofitService 中我們把getSearchBook方法返回的類型Call改為了Observable,也就是被觀察者。其他都沒變。然后就是創(chuàng)建RetrofitService 實體類:
RetrofitService service = retrofit.create(RetrofitService.class);
和上面一樣,創(chuàng)建完RetrofitService ,就可以調(diào)用里面的方法了:
Observable<Book> observable = service.getSearchBook("人間失格", null, 0, 1);
其實這一步,就是創(chuàng)建了一個rxjava中observable,即被觀察者,有了被觀察者,就需要一個觀察者,且訂閱它:
observable.subscribeOn(Schedulers.io())//請求數(shù)據(jù)的事件發(fā)生在io線程
.observeOn(AndroidSchedulers.mainThread())//請求完成后在主線程更顯UI
.subscribe(new DisposableObserver<Book>() {//訂閱
@Override
public void onComplete() {
//所有事件都完成,可以做些操作。。。
}
@Override
public void onError(Throwable e) {
e.printStackTrace(); //請求過程中發(fā)生錯誤
}
@Override
public void onNext(Book book) {//這里的book就是我們請求接口返回的實體類
}
}
在上面中我們可以看到,事件的消費在Android主線程,所以我們還要在build.gradle中添加如下依賴:
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
這樣我們就引入了RxAndroid,RxAndroid其實就是對RxJava的擴展。比如上面這個Android主線程在RxJava中就沒有,因此要使用的話就必須得引用RxAndroid。
實踐
接下來我們就看看,在一個項目中上面三者是如何配合的。我們打開Android Studio,新建一個項目取名為MVPSample。這個demo的功能也很簡單,就是點擊按鈕調(diào)用上面的那個測試接口,將請求下來書的信息顯示在屏幕上。首先我們來看一下這個工程的目錄結(jié)構(gòu):

我們可以看到,在項目的包名下,我們建了主要的文件夾:bean、data、presenter,ui;分別對應不同的功能。其中app文件夾中可以建一個Application類,用于設(shè)置應用全局的一些屬性,這里為了使項目更加簡單就沒有添加;然后,我們再來看看ui文件夾下,這個文件夾下主要放一些關(guān)于界面的東西。在里面我們又建了三個文件夾:activity、adapter、fragment,我想看名字你就清楚里面要放什么了。RetrofitHelper和APiService。RetrofitHelper主要用于Retrofit的初始化:
public class RetrofitHelper {
private Context mCntext;
OkHttpClient client = new OkHttpClient();
GsonConverterFactory factory = GsonConverterFactory.create(new GsonBuilder().create());
private static RetrofitHelper instance = null;
private Retrofit mRetrofit = null;
public static RetrofitHelper getInstance(Context context){
if (instance == null){
instance = new RetrofitHelper(context);
}
return instance;
}
private RetrofitHelper(Context mContext){
mCntext = mContext;
init();
}
private void init() {
resetApp();
}
private void resetApp() {
mRetrofit = new Retrofit.Builder()
.baseUrl(ApiService.BASE_URL)
.client(client)
.addConverterFactory(factory)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
public ApiService getServer(){
return mRetrofit.create(ApiService.class);
}
}
代碼并不復雜,其中resetApp方法,就是前面介紹的Retrofit的創(chuàng)建,getServer方法就是為了獲取ApiService接口類的實例化。然后定義了一個靜態(tài)方法getInstance用于獲取自身RetrofitHelper的實例化,并且只會實例化一次。
在正式的項目中model,view,presenter都需要根據(jù)需求創(chuàng)建對應的BaseView,BaseModel,BasePresenter;當前demo中只是簡單創(chuàng)建,后再后續(xù)封裝中繼續(xù)完善框架。
先創(chuàng)建一個BookInfoContract
public interface BookInfoContract {
interface IView extends BaseView {
void showResult(String msg);
// void onRequestPermissionSuccess();
//
// void onRequestPermissionSError();
}
interface IBookModel {
Observable<Book> getBookMsg(String name,String tag,int start,int count);
}
}
這是采用google官方demo的寫法,將相關(guān)的view和model接口寫到一個協(xié)議接口類中。方便查找和管理,每一個view,model,presenter都有對應的接口類相對應,這種寫法雖然類增加了,但是便于解耦,改動和維護方便;
具體實現(xiàn)步驟如下:
- 創(chuàng)建BookInfoModel,實現(xiàn)接口,并重寫獲取數(shù)據(jù)的方法
public class BookInfoModel implements BookInfoContract.IBookModel {
private ApiService mApiService;
public BookInfoModel(ApiService mApiService) {
this.mApiService = mApiService;
}
@Override
public Observable<Book> getBookMsg(String name, String tag, int start, int count) {
return mApiService.getSearchBooks(name, tag, start, count);
}
}
2.創(chuàng)建presenter,通過構(gòu)造傳入需要關(guān)聯(lián)的view,并初始化model;在getMsg()方法中,通過model中
getBookMsg()方法返回的被觀察者進入線程切換和事件訂閱;在訂閱回調(diào)中,調(diào)用view的方法對請求的結(jié)果進行處理;一般presenter持有view的引用,增加了耦合性,后面會進行優(yōu)化處理
public class BookPresenter {
private BookInfoContract.IView mView;
private BookInfoModel bookInfoModel;
private Book mBook;
public BookPresenter(BookInfoContract.IView mView) {
this.mView = mView;
bookInfoModel = new BookInfoModel(RetrofitHelper.getInstance((Context) mView).getServer());
}
//獲取數(shù)據(jù)
public void getMsg(String name, String tag, int start, int count) {
bookInfoModel.getBookMsg(name, tag, start, count)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Book>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Book value) {
mBook = value;
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
mView.showError("請求失敗");
}
@Override
public void onComplete() {
if (mView != null) {
mView.showResult(mBook.toString());
}
}
});
}
}
3.在mainActivity中實現(xiàn)接口 BookInfoContract.IView;通過注解初始化控件(在onDestroy中進行接觸注解)并獲取初始化presenter,在控件監(jiān)聽事件中。調(diào)用presenter的方法獲取數(shù)據(jù);
經(jīng)過以上幾步基本完成了mvp+rxjava+retrofit的框架搭建
項目地址:https://github.com/cruiseliang/MvpSample