首發(fā)于公眾號: DSGtalk1989
這兩尊大佛悴品,基本都是結(jié)伴出現(xiàn)的贷币,我們先什么都不管把依賴添加進(jìn)來,考慮到可能存在的版本號問題握联,之后將不再出現(xiàn)具體的版本號桦沉。
//Retrofit
implementation "com.squareup.okhttp3:logging-interceptor:${okhttp3_version}"
implementation "com.squareup.retrofit2:retrofit:${retrofit_version}"
implementation "com.squareup.retrofit2:converter-gson:${retrofit_version}"
implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofit_version}"
//RxJava
implementation "io.reactivex.rxjava2:rxjava:${rx_version}"
按照以往的習(xí)慣,我們需要一個(gè)類拴疤,來初始化Okhttp
和Retrofit
。并且加上一些我們需要的攔截独泞,比如日志等等呐矾。這些東西放在類的初始化中會(huì)比較合適。
class RetrofitFactory {
val retrofit: Retrofit
init {
//打印請求log
val logging = HttpLoggingInterceptor()
logging.level = if (BuildConfig.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
val mOkHttpClient = OkHttpClient.Builder()
.addInterceptor(logging)
.addInterceptor(headerInterceptor())
.build()
retrofit = Retrofit.Builder()
.baseUrl(AppConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(mOkHttpClient)
.build()
}
/**
* 攔截頭部
*/
private fun headerInterceptor(): Interceptor {
return Interceptor { chain ->
var request = chain.request()
//TODO 根據(jù)項(xiàng)目適配調(diào)整
request = request.newBuilder()
.addHeader("key", "value")
.build()
chain.proceed(request)
}
}
}
現(xiàn)在初始化完了懦砂,我們怎么去使用呢蜒犯。一般在java中都會(huì)去構(gòu)建一個(gè)單例來持有一個(gè)全局的Retrofit
對象。
所以需要用到kotlin的單例知識荞膘,這里涉及到的單例模式我們可以參考Kotlin的伴生對象()罚随。
companion object {
//Double Check
val instance: RetrofitFactory by lazy {
RetrofitFactory()
}
fun <T> createService(service: Class<T>): T {
return instance.retrofit.create(service)
}
}
我們直接使用lazy委托的方式實(shí)現(xiàn)單例,見委托羽资。這樣我們在每一次想要獲取到retrofit接口時(shí)淘菩,直接調(diào)用RetrofitFactory.createService(apiInterface)
即可。
那么既然我們還引入了Rxjava,要如何結(jié)合起來使用呢潮改?
先自定義一個(gè)全局網(wǎng)絡(luò)請求的Observer
狭郑,封裝網(wǎng)絡(luò)請求的各種情況,成功汇在,失敗翰萨,完成等等。
abstract class ResultObserver<T> : Observer<Response<T>> {
override fun onSubscribe(d: Disposable) {
if (!d.isDisposed) {
onRequestStart()
}
}
override fun onNext(reposnse: Response<T>) {
onRequestEnd()
if (reposnse.isSuccessful) {
try {
onSuccess(reposnse.body())
} catch (e: Exception) {
e.printStackTrace()
}
} else {
try {
onBusinessFail(reposnse.code(), reposnse.message())
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onError(e: Throwable) {
onRequestEnd()
try {
if (e is ConnectException
|| e is TimeoutException
|| e is NetworkErrorException
|| e is UnknownHostException
) {
onFailure(e, true)
} else {
onFailure(e, false)
}
} catch (e1: Exception) {
e1.printStackTrace()
}
}
override fun onComplete() {}
/**
* 請求開始
*/
open fun onRequestStart() {
}
/**
* 請求結(jié)束
*/
open fun onRequestEnd() {
}
/**
* 返回成功
*
* @param result
* @throws Exception
*/
@Throws(Exception::class)
abstract fun onSuccess(result: T?)
/**
* 返回失敗
*
* @param e
* @param isNetWorkError 是否是網(wǎng)絡(luò)錯(cuò)誤
* @throws Exception
*/
@Throws(Exception::class)
abstract fun onFailure(e: Throwable, isNetWorkError: Boolean)
/**
* 業(yè)務(wù)錯(cuò)誤
* 返回成功了,但是code錯(cuò)誤
*
* @param t
* @throws Exception
*/
@Throws(Exception::class)
open fun onBusinessFail(code: Int, message: String) {
}
}
首先是繼承Observer
糕殉,復(fù)寫四個(gè)接口方法:onSubscribe``onNext``onError``onComplete
亩鬼。然后加入了使用需要復(fù)寫的請求結(jié)果業(yè)務(wù)方法:成功onSuccess
,失敗onFailure
阿蝶。以及給出了一些定制化選項(xiàng):開始請求onRequestStart
雳锋,請求結(jié)束onRequestEnd
,業(yè)務(wù)錯(cuò)誤onBusinessFail
我們在RetrofitFactory
文件中加入針對Observable
的擴(kuò)展函數(shù)
fun <T> Observable<Response<T>>.executeResult(subscriber: ResultObserver<T>){
this.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber)
}
這樣赡磅,我們直接通過Observable
對象來調(diào)用executeResult
方法魄缚,即可控制生命周期。
我們來寫一個(gè)網(wǎng)絡(luò)請求的例子:
-
定義接口
interface UserService { @GET("user") fun getPersonInfo(): Observable<Response<User>> }
很好理解焚廊,跟java基本一致冶匹。
-
調(diào)接口請求網(wǎng)絡(luò)
RetrofitFactory.createService(WeatherService::class.java).getWeatherData() .executeResult(object : ResultObserver<WeatherData>() { override fun onSuccess(result: WeatherData?) { } override fun onFailure(e: Throwable, isNetWorkError: Boolean) { } })
就這兩步,就這么簡單咆瘟。
如果希望能夠再做更多的擴(kuò)展嚼隘,能夠讓我們的框架可以應(yīng)對更多的可能。比如我們需要將服務(wù)器返回的結(jié)果做一些轉(zhuǎn)換袒餐,將json數(shù)據(jù)轉(zhuǎn)成我們需要的單個(gè)對象或者是數(shù)組飞蛹,然后做一些修改繼續(xù)使用。我們可以借助Rxjava
的flatMap
操作符灸眼,為此打造一個(gè)FlatMapUtil
卧檐,專門處理類型切換。
實(shí)際上接下去的更多的和Rxjava有關(guān)焰宣,我們先來看個(gè)簡單的任務(wù)組合
//數(shù)據(jù)庫任務(wù)
val dbTask : Observable<User> = UsersDatabase.instance.userDao().getUserById("test")
//網(wǎng)絡(luò)任務(wù)
val netWorkTask : Observable<Response<WeatherData>>= RetrofitFactory.createService(WeatherService::class.java).getWeatherData()
//這兩個(gè)任務(wù)合并起來
val zipTask = Observable.zip(dbTask, netWorkTask, BiFunction<User, Response<WeatherData>, Response<WeatherData>>{
user, response ->
response
})
我們需要做兩個(gè)任務(wù)霉囚,而且必須要兩個(gè)任務(wù)都做完了之后才能繼續(xù)。
現(xiàn)在我們需要將網(wǎng)絡(luò)中獲得的東西做一些類型轉(zhuǎn)換匕积。我們活著放在第二步的網(wǎng)絡(luò)任務(wù)中盈罐,活著放在合并任務(wù)的BiFunction
中,其實(shí)最終差別不大闪唆。
val netWorkTask =
RetrofitFactory.createService(WeatherService::class.java).getWeatherData()
.flatMap {
val user = User(it.body()!!.info, "Tom")
val successful = it.isSuccessful
val response = if(successful) retrofit2.Response.success(user) else it
ObservableSource<User> { observer ->
if(successful){
observer.onNext(user)
} else {
observer.onError(Throwable(response.code().toString(), Throwable(response.errorBody().toString())))
}
}
}
FlatMapUtil
就是針對我們需要的flatMap
做了一層封裝盅粪,我們只需要去實(shí)現(xiàn)對象的轉(zhuǎn)換,不需要考慮觀察者的傳遞和異常處理悄蕾。
/**
* Response的實(shí)體類型轉(zhuǎn)換
*/
class FlatMapResponse2ResponseObject<T, R>(
private val response: Response<T>,
private val conversionCallBack: FlatConversionObjectInterface<T, R>
) : ObservableSource<Response<R>> {
override fun subscribe(observer: Observer<in Response<R>>) {
if (response.isSuccessful) {
val result = conversionCallBack.onConversion(response.body())
observer.onNext(Response.success(result))
} else {
observer.onError(Throwable(response.code().toString(), Throwable(response.errorBody().toString())))
}
}
}
interface FlatConversionObjectInterface<T, R> {
fun onConversion(t: T?): R
}
所以上面的代碼可以簡化成
val netWorkTask =
RetrofitFactory.createService(WeatherService::class.java).getWeatherData()
.flatMap {
FlatMapResponse2ResponseObject(it, object: FlatConversionObjectInterface<WeatherData, User>{
override fun onConversion(t: WeatherData?): User {
return User(it.body()!!.info, "Tom")
}
})
}