preface

Real development, a page is only a little request, usually have multiple requests, some need serial, parallel, some need to use the traditional method, if there are n interface, we will set up n interface callback, if is serial, also need to success or failure in the current interface, call next a request, one by one, It is really to kill obsessive-compulsive patients, and the code readability is very poor, new people often have to look at for a long time, not easy to maintain and prone to error.

This article uses the RxHttp request framework as a case demonstration. If you are not familiar with RxHttp, please check out the new generation of Http request wizard RxHttp in 30 Seconds

RxHttp has been rolling out since mid-April, and despite the fact that no one has learned or bothered to learn the new Http request framework, RxHttp has gained a huge following and currently has 415 stars on Github

RxHttp is an amazing Http request framework

Android has the most elegant implementation of file upload, download and progress monitoring

These two articles have been “Yu Gang said” and “Liu Wangshu” wechat public number exclusive original release, I think, this is also a kind of affirmation of RxHttp, welcome to experience RxHttp, its elegant writing and powerful functions, I believe you will fall in love with it.

Gradle rely on

  • OkHttp 3.14.x or later, API 21 is the minimum requirement. If you want compatibility below 21, please rely on OkHttp 3.12.x, API 9 is the minimum requirement for this version

  • The asXxx method is internally implemented through RxJava, and RxHttp version 2.2.0 has been removed from the internal RxJava, if you need to use RxJava, please rely on RxJava and inform RxHttp dependent RxJava version

Must be

Add the jitpack to your project’s build.gradle file as follows:

allprojects {
    repositories {
        maven { url "https://jitpack.io"}}}Copy the code

Note: As of RxHttp 2.6.0, there has been a full migration from JCenter to JITpack

// Required when using the RxHTTP-Compiler with kapt
apply plugin: 'kotlin-kapt'

android {
    // Required, Java 8 or higher
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation 'com. Making. Liujingxing. RXHTTP: RXHTTP: server'
    implementation 'com. Squareup. Okhttp3: okhttp: 4.9.0' As of RXHTTP v2.2.2, you need to manually rely on okhttp
    kapt 'com. Making. Liujingxing. RXHTTP: RXHTTP - compiler: server' // generate RxHttp class, pure Java project, please use annotationProcessor instead of kapt
 }
Copy the code

optional

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [
                    rxhttp_package: 'rxhttp'.// Optional, specify the RxHttp class package name
                    // Pass in the version of rxJava you depend on. You can pass in rxJava2, rxjava3, if you depend on RxJava, you must
                    rxhttp_rxjava: 'rxjava3'

                ]
            }
        }
    }
}
dependencies {
    implementation 'com. Making. Liujingxing. Rxlife: rxlife - coroutine: 2.1.0' // Manage the coroutine life cycle, page destruction, close requests
    
    //rxjava2 (either rxjava2 or Rxjava3, required when using asXxx method)
    implementation 'the IO. Reactivex. Rxjava2: rxjava: 2.2.8'
    implementation 'the IO. Reactivex. Rxjava2: rxandroid: 2.1.1'
    implementation 'com. Making. Liujingxing. Rxlife: rxlife - rxjava2:2.1.0' // Manage the RxJava2 lifecycle, page destruction, close requests

    //rxjava3
    implementation 'the IO. Reactivex. Rxjava3: rxjava: 3.0.6'
    implementation 'the IO. Reactivex. Rxjava3: rxandroid: 3.0.0'
    implementation 'com. Making. Liujingxing. Rxlife: rxlife - rxjava3:2.1.0' // Manage the RxJava3 life cycle, page destruction, close requests

    RxHttp has GsonConverter built in by default
    implementation 'com. Making. Liujingxing. RXHTTP: converter - fastjson: server'
    implementation 'com. Making. Liujingxing. RXHTTP: converter - Jackson: server'
    implementation 'com. Making. Liujingxing. RXHTTP: converter - moshi: server'
    implementation 'com. Making. Liujingxing. RXHTTP: converter - protobuf: server'
    implementation 'com. Making. Liujingxing. RXHTTP: converter - simplexml: server'
}
Copy the code

Note: After adding dependencies, you need to rebuild the project so that the annotation processor generates the RxHttp class. Also for kotlin users, use kapt instead of annotationProcessor

Finally, Rebuild the project (required) and the RxHttp class will be generated automatically

If the RxHttp class is not generated after the preceding steps, check the procedure

Next, let’s get started.

parallel

Now many pages are like this, above the Banner bar, below the Banner bar is the data list (assuming the student list), so it involves two interfaces, one is to get the Banner bar data, the other is to get the student list data, these two interfaces have no relationship, so we can implement in parallel

// The Banner Observable
Observable<Banner> bannerObservable = RxHttp.get("http://...")        
    .asClass(Banner.class);                                          
                                                                      
// The student Observable
Observable<List<Student>> studentObservable = RxHttp.get("http://...")
    .asList(Student.class);            
                                                                      
The merge operator in the RxJava combinator is used to merge two observed objects into one
Observable.merge(bannerObservable, studentObservable)                 
    .as(RxLife.asOnMain(this)) // Sense the lifecycle and automatically close the request
    .subscribe(o -> {                                                 
        // Request successful, callback 2 times, one time for Banner data, one time for Student list
        if (o instanceof Banner) {                                    
            // Get the banner data
        } else if (o instanceof List) {                               
            // Get student list data
        }                                                             
    }, throwable -> {                                                 
        // An exception occurs}, () - > {//2 requests are executed, and the UI is updated
    });                                                               
Copy the code

As you can see, we first get the two Observables of Banner and Student using the RxHttp class. Then we merge the two Observables into one using the merge operator and subscribe to the observer. This will get the Banner and Student data in the onNext callback and update the UI in the onComplete callback.

But is that the end? If the Banner interface fails, the Student message will stop working. If the Banner interface fails, the Student message will stop working. If the Banner interface fails, the Student message will stop working. RxJava resumenext (onErrorReturn, onErrorReturn) If you are not familiar with the RxJava error handling mechanism, check out the RxJava error handling details. Here, we use the onErrorResumeNext operator, as follows

// The Banner Observable
Observable<Banner> bannerObservable = RxHttp.get("http://...")        
    .asClass(Banner.class)
    .onErrorResumeNext(Observable.empty()); // An exception occurs. Send an empty Observable
                                                                      
// The student Observable
Observable<List<Student>> studentObservable = RxHttp.get("http://...")
    .asList(Student.class);            
                                                                      
The merge operator in the RxJava combinator is used to merge two observed objects into one
Observable.merge(bannerObservable, studentObservable)                 
    .as(RxLife.asOnMain(this)) // Sense the lifecycle and automatically close the request
    .subscribe(o -> {                                                 
        // Request successful, callback 2 times, one time for Banner data, one time for Student list
        if (o instanceof Banner) {                                    
            // Get the banner data
        } else if (o instanceof List) {                               
            // Get student list data
        }                                                             
    }, throwable -> {                                                 
        // An exception occurs}, () - > {//2 requests are executed, and the UI is updated
    });
Copy the code

We just added onErrorResumeNext(Observable.Empty ()), which is an Observable that doesn’t fire any events. So, if the Banner’s Observable gets an exception, no events are emitted, and the Student Observable continues to execute, only receiving one callback from the Student in the onNext callback (if the request is successful). And then execute the onComplete callback to update the UI so that even if the Banner interface fails, we can still get the student list data to work. To make sure that interface A does not affect interface B, but interface B can affect interface A. To ensure that interface A and interface B do not affect each other, handle exceptions for interface A and interface B. If there are three, four or more requests, you can use the Observable.mergeArray operator.

serial

Let’s say we have a requirement to log in immediately after registration. In this case, we can only do it serially. In this case, we use the flatMap operator of RxJava to do it

flatMap

RxHttp.postForm("http://...") // Send the registration request
    .add("userName"."zhangsan")
    .add("password"."123456")
    .asClass(Register.class)
    .flatMap((io.reactivex.functions.Function<Register, ObservableSource<User>>) register -> {
        // Register successfully, get the registration information to log in, and return the User object
        return RxHttp.get("http://...") // Send the login request
                .add("userId", register.getUserId())
                .add("password", register.getPassword())
                .setSync()      // Synchronize the request
                .asClass(User.class);
    })
    .as(RxLife.asOnMain(this)) // Sense the lifecycle and automatically close the request
    .subscribe(user -> {
        // Register and login successfully, get user information
    }, throwable -> {
        // An exception occurs. Registration or login fails
    });
Copy the code

Note: The asXXX series of methods in RxHttp internally enable THE IO thread to execute Http requests by default, so when we send a single request, there is no need to specify the request execution thread; However, when multiple requests are serial, we want one thread to execute multiple requests for efficiency, so we need to use the setSync method to specify that the current thread initiates the synchronous request.

As you can see, here we use the flatMap operator. When successfully registered, we will go inside the flatMap to log in. The successful login will fetch the User object and call back the observer.

summary

RxHttp is seamlessly connected to RxJava. You can get an Observable

object using asXXX methods, and then combine RxJava merge and flatMap to gracefully implement serial and parallel Http requests. If you are familiar with RxJava, you can implement many interesting features, such as setting timeout for a single request, automatic retry n times for failed requests, and so on.

Finally, all the credit goes to the power of RxJava, thanks to RxJava, hats off to !!!!