代碼地址:https://github.com/DarkPointK/RxTrofit.git
Retrofit是Square公司開發的一個類型安全的Java和Android 的REST客戶端庫。來自官網的介紹:java
A type-safe HTTP client for Android and Javareact
Rest API是一種軟件設計風格,服務器做爲資源存放地。客戶端去請求GET,PUT, POST,DELETE資源。而且是無狀態的,沒有session的參與。android
Retrofit是基於OkHttp的網絡接口的封裝,之因此被中小型項目所推行使用,仍是得力於它的相對規範化、安全性、可操做性git
RxJava 在 GitHub 主頁上的用這樣一句話形容本身是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM 上使用可觀測的序列來組成異步的、基於事件的程序的庫)。這就是 RxJava ,歸納得很是精準,但這句話更像是對RxJava的一個總結。其實, 簡單來講RxJava 的本質能夠壓縮爲異步這一個詞。說到根上,它就是一個實現異步操做的庫,而別的定語都是基於這之上的。用我我的的話來講,RxJava既是AsyncTask 的終極形態。github
前面,咱們簡單的瞭解了一下Retrofit與RxJava,本文的着重點在你們已經會用的前提下,仍是要和你們探討如何去應用以及封裝他們。想要在項目中使用他們,第一步即是在Gradle中添加相應的Dependencies:編程
compile 'com.squareup.retrofit2:retrofit:2.3.0'api
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//retrofit2的Json轉換器(默認用Gson)安全
compile 'com.squareup.okhttp3:okhttp:3.9.0'服務器
compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'//okhttp提供的請求日誌攔截器網絡
compile 'io.reactivex:rxjava:1.3.0'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
接下來,建立必要的類與接口,固然,別忘了manifests中添加權限:
<uses-permission android:name="android.permission.INTERNET"/>
新建一個提供給Retrofit初始化,用於描述服務端接口的Interface,我在這裏調用的是豆瓣的一個公開接口:
1 interface HttpInterface { 2 3 @GET("top250") 4 5 fun getTopMovie(@Query("start") start: Int, @Query("count") count: Int): Observable<GetMovie> 6 7 }
這裏定義了一個GET目錄top250,參數爲start,count,返回值則是一個Observable綁定了一個接口返回數據的實體類
接着新建一個用於初始化Retrofit封裝請求的方法類:
1 class HttpMethod { 2 3 companion object { 4 5 val httpMethod: HttpMethod = Holder.INSTANCE 6 7 } 8 9 private object Holder { 10 11 val INSTANCE = HttpMethod() 12 13 } 14 15 } 16 17
因爲網絡請求在業務邏輯中將頻繁的被調用,因此須要咱們在這裏建立一個當前類的單例,以免被屢次實例化。
當咱們建立好單例後,即可以放心的來初始化咱們即將須要用到的3個關鍵的成員變量了,retrofit的回調適配器咱們在這選用RxJavaCallAdapterFactory:
1 private var okclient = OkHttpClient.Builder() 2 3 .addInterceptor(HttpLoggingInterceptor(). 4 5 setLevel(HttpLoggingInterceptor.Level.BODY)) 6 7 .addNetworkInterceptor(OAuthIntercepter()) 8 9 connectTimeout(8, TimeUnit.SECONDS) 10 11 readTimeout(15, TimeUnit.SECONDS) 12 13 writeTimeout(15, TimeUnit.SECONDS) 14 15 build() 16 17 18 19 private var retrofit: Retrofit = Retrofit.Builder() 20 21 .client(okclient) 22 23 .baseUrl("https://api.douban.com/v2/movie/") 24 25 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 26 27 .addConverterFactory(GsonConverterFactory 28 29 .create(GsonBuilder().serializeNulls().setLenient().create()) 30 31 ) 32 33 .build() 34 35 36 37 private var httpInterface = retrofit.create(HttpInterface::class.java) 38 39
咱們首先Builder了一個OkhttpClient對象,併爲其添加了一個請求日誌的攔截器,緊接着初始化了Retrofit爲其添加RxJavaCallAdapter,最後以HttpInterface爲參數將retrofit建立爲HttpInterface,這樣咱們就能夠用httpInterface封裝一個調用以前所描述的getTopMovie接口方法,在這個方法中咱們會將Retrofit完成請求返回的被觀察者訂閱起來,在這個過程當中咱們能夠對返回的數據流經過RxJava豐富的操做符進行自由的處理。
定義一個getTopMovie方法用於在業務邏輯中調用retrofit接口,這裏咱們須要三個參數,其中前兩個爲GET請求所須要的參數,而subscriber用來訂閱retrofit接口返回的Observable:
1 fun getTopMovie(start: Int, count: Int, subscriber: Subscriber<GetMovie>) {}
這樣咱們即可以在客戶端的業務邏輯中經過調用HttpMethod. INSTANCE .getTopMovie(…)來請求接口,可是此時咱們尚未將Observable訂閱上,因此如今咱們須要完善下這個方法:
1 fun getTopMovie(start: Int, count: Int, subscriber: Subscriber<GetMovie>) { 2 3 toSubscriber(httpInterface.getTopMovie(start,count),subscriber) 4 5 }
能夠看到咱們在方法體中添加了一句toSubscriber(…),至此咱們便將subscriber訂閱上httpInterface.getTopMovie(…)返回的Observable了,至於這個subscriber參數具體如何實現,在下一節將會介紹,咱們先來了解下這個toSubscriber的工做是如何實現的:
1 private fun toSubscriber (observable: Observable<T>, subscriber: Subscriber<T>) { 2 3 observable.subscribeOn(Schedulers.io()) 4 5 .unsubscribeOn(Schedulers.io()) 6 7 .observeOn(AndroidSchedulers.mainThread()) 8 9 .doOnError {} 10 11 .subscribe(subscriber) 12 13 }
熟悉RxJava的碼友應該一眼變冷看出這是一段典型的訂閱流程,是的,這是經過RxJava流式編程實現最簡單的訂閱事件。
至此,咱們便已經能夠再業務邏輯中正常使用getTopMovie(…)了:
1 HttpMethod.httpMethod.getTopMovie(1,1,object :Subscriber<GetMovie>(){ 2 3 override fun onNext(t: GetMovie?) { 4 5 } 6 7 8 9 override fun onCompleted() { 10 11 } 12 13 14 15 override fun onError(e: Throwable?) { 16 17 } 18 19 20 21 })
咱們已經知道如何簡單的方式經過RxJava調用Retrofit接口,但這每每不能的知足咱們的追求。
在項目中,每每咱們會定義這樣的返回體結構:
{ "code": 1, "data": [ ], "msg": "success" }
咱們會在全部接口獲得3個全局相應參數,其中code表明結果碼,msg表明附加信息,而data則是對應的響應數據會因接口而異,咱們每每須要每一個接口根據code去判斷接下來的操做,那麼咱們應該怎樣封裝才能讓每一個統一進行處理呢,接下來咱們改一改前面的訂閱流程:
data class GetMovie<T>( @SerializedName("count") var count: Int?, //20 @SerializedName("start") var start: Int?, //0 @SerializedName("total") var total: Int?, //250 @SerializedName("subjects") var subjects: T?, @SerializedName("title") var title: String? //豆瓣電影Top250 )
這裏咱們切當subjects之外的參數爲固有的全局響應參數,而subjects的List元素類型則不定,咱們須要顯示的綁定GetMovie以在訂閱時能夠取得全局響應參數而不用關心subjects的類型,改動的包括接口定義在內用到實體類泛型的地方:
interface HttpInterface { @GET("top250") fun getTopMovie(@Query("start") start: Int, @Query("count") count: Int): Observable<GetMovie<List<Subject>>> }
接口表示咱們獲取到的返回數據將會是GetMovie類的結構,而且泛型指出subjects的類型是個Subject的List,接下來在將HttpMethod中封裝請求的方法也修改下:
fun getTopMovie(start: Int, count: Int, subscriber: Subscriber<List<Subject>>) {
toSubscriber(httpInterface.getTopMovie(start, count), subscriber)
}
因爲咱們須要在RxJava處理數據的流程中,統一對全局響應參數進行判斷,因此訂閱的流程便成爲了咱們工做主要進行的場所:
1 private fun <T> toSubscriber(observable: Observable<GetMovie<T>>, subscriber: Subscriber<T>) { 2 3 observable 4 5 .compose { 6 7 it.flatMap { result -> 8 9 if (result.count!! > 0) 10 11 createData(result.subjects) 12 13 else 14 15 Observable.error(Throwable("")) 16 17 } 18 19 } 20 21 .subscribeOn(Schedulers.io()) 22 23 .unsubscribeOn(Schedulers.io()) 24 25 .observeOn(AndroidSchedulers.mainThread()) 26 27 .doOnError {} 28 29 .subscribe(subscriber) 30 31 }
能夠看到這裏咱們使用了兩個RxJava的操做符分別是compose與flatMap,通過flatMap的轉換返回一個新的被觀察者綁定的數據即是subjects:
1 private fun <T> createData(data: T): Observable<T> { 2 3 return Observable.create { subscriber -> 4 5 try { 6 7 subscriber.onNext(data) 8 9 subscriber.onCompleted() 10 11 } catch (e: Exception) { 12 13 subscriber.onError(e) 14 15 } 16 17 } 18 19 }
最後,業務邏輯中這樣調用:
1 HttpMethod.httpMethod.getTopMovie(1,1,object :Subscriber<List<Subject>>(){ 2 3 override fun onNext(t: List<Subject>?) { 4 5 sample_text.text =t?.get(0)?.originalTitle 6 7 } 8 9 override fun onCompleted() { 10 11 } 12 13 override fun onError(e: Throwable?) { 14 15 } 16 17 })
傳入參數及Subscriber,通過compose轉換在onNext中獲得List<Subject>。
至此對RxJava與Retrofit的封裝告一段落了,經過compose操做符,咱們能夠隨心的去操做數據流,以獲得咱們想要的數據,而且還有其餘豐富的操做符,例如repeatWhen,retryWhen ,doOnError,delay等等實用的方法,在稍後會和你們作進一步介紹。