上一篇中簡單介紹了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())
當(dāng)然你還需要在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就是我們請求接口返回的實體類
}
}
在上面中我們可以看到,事件的消費(fèi)在Android主線程榕吼,所以我們還要在build.gradle中添加如下依賴:
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
這樣我們就引入了RxAndroid饿序,RxAndroid其實就是對RxJava的擴(kuò)展。比如上面這個Android主線程在RxJava中就沒有羹蚣,因此要使用的話就必須得引用RxAndroid原探。
實踐
接下來我們就看看,在一個項目中上面三者是如何配合的度宦。我們打開Android Studio踢匣,新建一個項目取名為MVPSample。這個demo的功能也很簡單戈抄,就是點擊按鈕調(diào)用上面的那個測試接口离唬,將請求下來書的信息顯示在屏幕上。首先我們來看一下這個工程的目錄結(jié)構(gòu):
我們可以看到划鸽,在項目的包名下输莺,我們建了主要的文件夾:bean戚哎、data、presenter,ui;分別對應(yīng)不同的功能嫂用。其中app文件夾中可以建一個Application類型凳,用于設(shè)置應(yīng)用全局的一些屬性驶社,這里為了使項目更加簡單就沒有添加嗦董;然后,我們再來看看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);
}
}
代碼并不復(fù)雜撇寞,其中resetApp方法顿天,就是前面介紹的Retrofit的創(chuàng)建,getServer方法就是為了獲取ApiService接口類的實例化蔑担。然后定義了一個靜態(tài)方法getInstance用于獲取自身RetrofitHelper的實例化牌废,并且只會實例化一次。
在正式的項目中model,view,presenter都需要根據(jù)需求創(chuàng)建對應(yīng)的BaseView,BaseModel,BasePresenter;當(dāng)前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都有對應(yīng)的接口類相對應(yīng)莫绣,這種寫法雖然類增加了,但是便于解耦悠鞍,改動和維護(hù)方便对室;
具體實現(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()方法返回的被觀察者進(jìn)入線程切換和事件訂閱;在訂閱回調(diào)中么翰,調(diào)用view的方法對請求的結(jié)果進(jìn)行處理牺汤;一般presenter持有view的引用,增加了耦合性浩嫌,后面會進(jìn)行優(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中進(jìn)行接觸注解)并獲取初始化presenter,在控件監(jiān)聽事件中补胚。調(diào)用presenter的方法獲取數(shù)據(jù);
經(jīng)過以上幾步基本完成了mvp+rxjava+retrofit的框架搭建
項目地址:https://github.com/cruiseliang/MvpSample