代码地址: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等等实用的方法,在稍后会和你们作进一步介绍。