This article introduces a detailed explanation of the simple packaging of Kotlin + Retrofit + RxJava. It is shared with you. The details are as follows:
Instantiate Retrofit
object RetrofitUtil { val CONNECT_TIME_OUT = 30//Connection timeout duration x seconds val READ_TIME_OUT = 30//Read data timeout duration x seconds val WRITE_TIME_OUT = 30//Write data timeout duration x seconds val retrofit: Retrofit by lazy { Log.d("RetrofitUtil", "retrofit init lazy") Retrofit.Builder() .baseUrl("http://gank.io/api/") //This article uses GitHub API as an example.addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(getOkHttpClient()) .build() } private fun getOkHttpClient(): OkHttpClient { val builder = OkHttpClient.Builder() builder.connectTimeout(CONNECT_TIME_OUT.toLong(), TimeUnit.SECONDS) .writeTimeout(WRITE_TIME_OUT.toLong(), TimeUnit.SECONDS) .readTimeout(READ_TIME_OUT.toLong(), TimeUnit.SECONDS) if (BuildConfig.DEBUG) { builder.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) } else { builder.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.NONE)) } // Set request header builder.addInterceptor { chain -> val time = (System.currentTimeMillis() / 1000).toString() + "" val requestBuilder = chain.request().newBuilder() requestBuilder.addHeader("time", time) chain.proceed(requestBuilder.build()) } return builder.build() }} Return to data encapsulation
class Response<T> { var error: Boolean = false var results: T? = null}The development API of gank.io was used in the demo. The return format of the previous general project was code + message + T format.
Api interface error/exception unified handling class
class ApiException : Exception { var code: Int = 0//Error code var msg: String? = null//Error message constructor(throwable: Throwable, code: Int) : super(throwable) { this.code = code } constructor(code: Int, msg: String) { this.code = code this.msg = msg }}Define ExceptionFunction handles onErrorResumeNext:
class ExceptionFunction<T> : Function<Throwable, Observable<T>> { override fun apply(@NonNull throwable: Throwable): Observable<T> { Log.e("ExceptionFunction", throwable.message) return Observable.error(ExceptionEngine().handleException(throwable)) }}/** * Error/Exception Handling Tool*/class ExceptionEngine { val UN_KNOWN_ERROR = 1000//Unknown error val ANALYTIC_SERVER_DATA_ERROR = 1001//Paste (server) data error val CONNECT_ERROR = 1002//Network connection error val TIME_OUT_ERROR = 1003//Network connection timeout fun handleException(e: Throwable): ApiException { val ex: ApiException if (e is ApiException) { //Error returned by the server return e } else if (e is HttpException) { //HTTP error ex = ApiException(e, e.code()) ex.msg = "Network error:" + ex.code return ex } else if (e is JsonParseException || e is JSONException || e is ParseException || e is MalformedJsonException) { //Parse data error ex = ApiException(e, ANALYTIC_SERVER_DATA_ERROR) ex.msg = "Parse error" return ex } else if (e is ConnectException) {//Connect network error ex = ApiException(e, CONNECT_ERROR) ex.msg = "Connection failed" return ex } else if (e is SocketTimeoutException) {//Network timeout ex = ApiException(e, TIME_OUT_ERROR) ex.msg = "Network timeout" return ex } else { //Unknown error ex = ApiException(e, UN_KNOWN_ERROR) ex.msg = e.message return ex } }} Encapsulation request processing
object Rx { /** * Rxlifecycle binding lifecycle*/ fun <T, E> get(observable: Observable<Response<T>>, lifecycleProvider: LifecycleProvider<E>): Observable<T> { // Request the binding lifecycle to prevent memory leakage, and return the null pointer error caused by the page being destroyed after the callback if (lifecycleProvider is RxAppCompatActivity) { val rxAppCompatActivity = lifecycleProvider as RxAppCompatActivity observable.compose(rxAppCompatActivity.bindUntilEvent(ActivityEvent.DESTROY)) } else if (lifecycleProvider is RxFragment) { val rxFragment = lifecycleProvider as RxFragment observable.compose(rxFragment.bindUntilEvent(FragmentEvent.DESTROY)) } return observable .compose(HandleResult()) .onErrorResumeNext(ExceptionFunction()) } /** * Partial background requests*/ fun <T> get(observable: Observable<Response<T>>): Observable<T> { return observable .compose(HandleResult()) .onErrorResumeNext(ExceptionFunction()) } private class HandleResult<T> : ObservableTransformer<Response<T>, T> { override fun apply(upstream: Observable<Response<T>>): ObservableSource<T> { return upstream.flatMap { response -> createResult(response) } .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) } } private fun <T> createResult(response: Response<T>): Observable<T> { return Observable.create({ subscriber -> if (response.error) throw ApiException(-1, "Server Exception") // Generally speaking, your own server exception will return the corresponding code and message else response.results?.let { subscriber.onNext(response.results!!) } ?: subscriber.onComplete() }) }} Define HttpObserver unified processing return
abstract class HttpObserver<T> : Observer<T> { /** * Tag is a special case*/ private var resultNull: Boolean = true override fun onComplete() { // Special case: OnNext will be skipped when the request is successful, but T == null, and it still needs to be processed successfully if (resultNull) onSuccess(null) } override fun onSubscribe(d: Disposable) { // Dialog can be added here } override fun onError(e: Throwable) { if (e is ApiException) { onError(e.code, e.msg) } else { onError(0, e.message) } } override fun onNext(t: T) { resultNull = false onSuccess(t) } abstract fun onSuccess(t: T?) /** * Unified processing failed, such as login failure, etc. * @param code * @param msg */ open fun onError(code: Int, msg: String?) { }} Api
class Result { var _id: String? = null var createdAt: String? = null var desc: String? = null var publishedAt: String? = null var source: String? = null var type: String? = null var url: String = "" var isUsed: Boolean = false var who: String? = null var images: List<String>? = null /** * Girl's small picture*/ fun meiziSmallUrl(): String { val meizi = url return meizi.replace("large", "small") }}interface Apiservice { @GET("data/{type}/10/{page}") fun getGank(@Path("type") type: String, @Path("page") page: Int): Observable<Response<List<Result>>>}object Api { val apiservice: Apiservice by lazy { Log.d("Api", "apiservice create lazy") RetrofitUtil.retrofit.create(Apiservice::class.java) }} use
override fun loadData() { Rx.get(Api.apiservice.getGank(getType(), mIntPage), this).subscribe(object : HttpObserver<List<Result>>() { override fun onSuccess(t: List<Result>?) { //getDataSuccess(t) } override fun onError(code: Int, msg: String?) { super.onError(code, msg) //getDataFailed() } }) }The Rxlifecycle binding lifecycle is used to deal with possible memory leaks. Fragment and Activity need to inherit the corresponding base class of Rx.
Practice program
Meizikt Gank.io Android client, using Kotlin + Retrofit2 + RxJava
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.