RxJava can also request networks as gracefully as a co program

Keywords: Retrofit network JSON Android

RxJava can also request networks as gracefully as a co program

Retrofit & coroutines and retrofit & rxjava

I believe that everyone here can say a lot about the network request framework, but I'm not going to talk about the network request framework today. Let's talk about the difference between the co process touted by you and the RxJava abandoned by you, and whether RxJava can be as convenient and quick as the co process.

This article is based on Retrofit2.9.0, which is slightly different from the previous version. Please note.

1, Create Retrofit

The first step is to configure Retrofit

object RetrofitManager {

    fun <K> create(clazz: Class<K>) : K = getRetrofit().create(clazz)

    private fun getRetrofit(): Retrofit {
        // Get an instance of retrofit
        return Retrofit.Builder()
             //url must end with '/', otherwise IllegalArgumentException will be reported
            .baseUrl(ApiService.BASE_URL)
            .client(getOkHttpClient())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build()

    }

    private fun getOkHttpClient(): OkHttpClient {
        //Add a log interceptor to print all logs
        val httpLoggingInterceptor = HttpLoggingInterceptor()
        //You can set the level of request filtering
        httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY

        return OkHttpClient.Builder()
            .addInterceptor(httpLoggingInterceptor) //Log, see the response of all requests
            .connectTimeout(15L, TimeUnit.SECONDS)
            .readTimeout(15L, TimeUnit.SECONDS)
            .writeTimeout(15L, TimeUnit.SECONDS)
            .proxy(Proxy.NO_PROXY)
            .build()
    }
}

2, Create Service interface

The interface sources used in this demonstration are Play android

interface ApiService {

    companion object{
        const val BASE_URL = "https://www.wanandroid.com/"
    }

    @GET("article/list/{page}/json")
    fun getList(
        @Path("page") page: Int
    ) : Observable<HomeListBean>

    @GET("banner/json")
    fun getBannerList(): Call<BannerBean>

    @POST("postxxx/xxx")
    fun postMsg(@Body json : RequestBody) : Observable<BaseBean>
}

OK, let's review the network requests made by the traditional RxJava+Retrofit.
First, we encapsulate RxJava. Although it may be different, it is also the same.

fun <T : Basexxx> request(){
        check: Boolean = true,
        function: Function<Boolean, ObservableSource<T>>,
        next: Consumer<T>,
        error: Consumer<Throwable> = Consumer {
            finishRefreshorLoadData = true
            errorLiveData.postValue(it)
        }
    ) {
        val disposable = Observable.just(check)
            .subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .filter { t -> t }
            .flatMap(function)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(next, error)
        addSubscription(disposable)
    }

And then the request might be like this

  request(
            function = Function<Boolean, ObservableSource<xxxBen>>{
            	//Network request
                model.getList(1)
            },
            next = Consumer{
                liveDataVideo.postValue(it)
            }
        )

Before I knew about the process, at first glance, it seemed that there was nothing wrong with it. It was just not simple enough.
Let's look at the network request of the process:

  GlobalScope.launch {
            val bean = model.getBannerList().await()
            liveData.postValue(bean)
   }

Take a breath.
Because Retrofit is version 2.9, the cooperation process is directly encapsulated in Retrofit. As a developer, we don't need to go to many encapsulation to call directly.
The comparison between the two is clear at a glance. Since the process can be so simple, can RxJava?

3, RxJava repackage

Certainly.
First of all, let's analyze the following parts of network requests that we care about:
1. Direct processing of request success results
2. Don't care about request exceptions
3. Destroy the interface to cancel the existing request
In the end, it was sealed as follows

fun <T : BaseBean> Observable<T>.onResult(
        next : (T) -> Unit
    ){
        this onResult Consumer {
            //Return judgment and background agreement are performed here
            if (!TextUtils.equals(it.errorCode,"200")){
                errorLiveData.value = it.errorMsg
                return@Consumer
            }
            next(it)
        }
    }

Look at the final results

    fun getList(){
        //RxJava
        model.getList(0).onResult {
            liveData2.value = it
        }

    }

    fun getBannerList(){
        //Synergetic process
        GlobalScope.launch {
            val bean = model.getBannerList().await()
            liveData.postValue(bean)
        }

    }

Well, that's perfect.
Although the protocol can replace RxJava in network request, the streaming programming of RxJava is not the substitute of the protocol, which is better or worse is difficult to define. I don't know what you like.
Enclose RxJava's encapsulation code at the end

open class BaseViewModel : ViewModel(),IViewModel {

    val errorLiveData: MutableLiveData<String> = MutableLiveData()
    private var compositeDisposable = CompositeDisposable()

    override fun onCreate(owner: LifecycleOwner) {
        //establish
    }

    override fun onDestroy(owner: LifecycleOwner) {
        //Destruction
        detachView()
        //Remove lifecycle monitor observer
        owner.lifecycle.removeObserver(this)
    }

    override fun onLifecycleChanged(owner: LifecycleOwner, event: Lifecycle.Event) {
        //Life cycle state change
    }

    //Generics can be < T: basebean >, or < T: List < basebean > >
    //Here is the extension function of Observable, you can also change it to the extension function of Flowable
    fun <T : BaseBean> Observable<T>.onResult(
        next: Consumer<T>,
        error: Consumer<Throwable> = Consumer {
            errorLiveData.postValue(it.message)
        }
    ) {
        val disposable = this.subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(next, error)
        addSubscription(disposable)
    }

    private infix fun <T : BaseBean> Observable<T>.onResult(
        next: Consumer<T>
    ) {
        this.onResult(next,Consumer {
            errorLiveData.postValue(it.message)
        })
    }

    fun <T : BaseBean> Observable<T>.onResult(
        next : (T) -> Unit
    ){
        this onResult Consumer {
            //Return judgment here
            /*if (!TextUtils.equals(it.errorCode,"200")){
                errorLiveData.value = it.errorMsg
                return@Consumer
            }*/
            next(it)
        }
    }


    private fun addSubscription(disposable: Disposable) {
        compositeDisposable.add(disposable)
    }

    private fun detachView() {
        //Ensure that all active subscriptions are cancelled at the end of the activity
        if (!compositeDisposable.isDisposed) {
            compositeDisposable.clear()
        }
    }
}

Project address

Posted by prawn_86 on Tue, 16 Jun 2020 01:36:20 -0700