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() } } }