1, the preface

RxHttp has been popular with Android developers since it was first launched in April, 2016. As of May, it has reached 2000+ Star on Github. For this reason, I have set up my own RxHttp&RxLife group (group number: 378530627) At present, there are more than 500 people in the group, and many friends have proposed a lot of valuable ideas, which makes RxHttp has been sticking to the present, here, thank you for your love.

All this time, people have been asking me, Doesn’t Retrofit smell good? Before did not know how to answer this question, now I want to say, xiang!! Retrofit is undoubtedly the player with the highest overall score so far, but it also has its drawbacks.

RxHttp compared to Retrofit, function, both can be implemented, there is no much difference, more differences reflect the use of functionality, that is, ease of use, such as file upload/download/progress monitoring operation, RxHttp and simple API, can be said to roll retrofit; In addition, the ease of use of baseUrl, public parameters/request headers, request encryption and decryption is better than retrofit; In my opinion, the biggest advantages of RxHttp are its near zero cost of getting started, minimal API and high scalability. After reading this article, I believe you will agree.

So there are no disadvantages to RxHttp? After all, RxHttp has only been around for 8 months, and I’ve been maintaining it all by myself. Of course, this is not to say that RxHttp is unstable. RxHttp was used in real projects for nearly 2 years before it was open source, and then it was open source in April of ’19. At present, more than 30 versions have been iterated, and the number of people using it is not a small number. It can be said that it is very stable.

See more features

RxHttp, a more elegant coroutine experience than Retrofit

RxHttp is perfect for Android 10/11 upload/download/progress monitoring

RxHttp Optimal solution for network Http cache

2, introduction,

RxHttp is based on the secondary encapsulation of OkHttp, and seamless with RxJava, a chain can send any request. The main advantages are as follows:

1. It can be started in 30 seconds and costs very little to learn

2. Perfect Kotlin coroutine support

3. The most elegant handling of multiple baseurLs and dynamic BaseUrl in history

4. The most elegant unified handling of errors in history without breaking Lambda expressions

5. The most elegant implementation of file upload/download and progress monitoring, and support breakpoint download

6. Support Gson, Xml, ProtoBuf, FastJson and other third-party data parsing tools

7. Support Get, Post, Put, Delete and other arbitrary request mode, can be customized request mode

8. Support the Activity/fragments/View/ViewModel/any class, the request will be automatically closed

9. Support global encryption and decryption, add public parameters and head, network cache, support for a request to set separately

3, use,

3.1. Preparations

Gradle rely on

  • OkHttp 3.14.x or later, the minimum requirement is API 21. If you want to be compatible with API 21 or below, please rely on OkHttp 3.12.x, which requires API 9

  • The asXxx method is implemented internally through RxJava, and RxHttp version 2.2.0, RxJava has been excluded from the internal, if you need to use RxJava, please rely on RxJava and tell RxHttp to rely on the 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: RxHttp has been fully migrated from JCenter to JITPack since version 2.6.0

// Must be used when kapt relies on rxhttp-compiler
apply plugin: 'kotlin-kapt'

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

dependencies {
    implementation 'com. Making. Liujingxing. RXHTTP: RXHTTP: 2.6.5'
    implementation 'com. Squareup. Okhttp3: okhttp: 4.9.1' // From RXHTTP v2.2.2, you need to manually rely on okhttp
    kapt 'com. Making. Liujingxing. RXHTTP: RXHTTP - compiler: 2.6.5' // 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 the version of RxJava that you depend on. You can pass rxJavA2, rxJavA3, but you must if you depend on RxJava
                    rxhttp_rxjava: 'rxjava3'

                ]
            }
        }
    }
}
dependencies {
    implementation 'com. Making. Liujingxing. Rxlife: rxlife - coroutine: 2.1.0' // Manage the coroutine life cycle, page destruction, close requests
    
    //rxjava2 (rxjava2 /Rxjava3)
    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 lifecycle, page destruction, close requests

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

Note: After adding a dependency, you need to rebuild the project and the handler will generate the RxHttp class. Also for kotlin users, use kapt instead of annotationProcessor

Finally, Rebuild the project (as required) and the RxHttp class is automatically generated

After the preceding steps, the RxHttp class is not generated. Please check the steps if the RxHttp class is not generated

Configure the default BaseUrl

Use the @defaultdomain annotation to configure the DefaultDomain name as follows:

public class Url {
    @DefaultDomain // Set this to the default domain name
    public static String baseUrl = "https://www.wanandroid.com/";
}
Copy the code

This step is optional. The @defaultDomain annotation is introduced here. For more information about domain names, see section 3.6 —- Multiple Domain names/Dynamic Domain names

3.3. Request trilogy

Note:RxHttp + coroutinesDocumentation, please checkRxHttp, a more elegant coroutine experience than Retrofit

The code says, send a simple request, as follows

RxHttp.get("http://...")  // The first step is to determine the request type by the methods of GET, postXxx, putXxx, etc
    .asString()           // The second step is to determine the return data type through the asXxx series of methods
    .subscribe(s -> {     // The third step, the subscription callback (this step is the same as RxJava subscription Observer)
        // The request succeeded
    }, throwable -> {                                  
        // The request failed
    });                                                
Copy the code

Yes, no doubt, it’s as simple as that. Say the important things three times

Any request, any returned data type, follows the request trilogy

Any request, any returned data type, follows the request trilogy

Any request, any returned data type, follows the request trilogy

At this point, you’ve got the essence of RxHttp, we just need to remember the request trilogy and use RxHttp will be handy.

3.3.1 Part I: Determining the Request Type

RxHttp internally provides a total of 14 request methods, as follows:

RxHttp.get(String)              // Get request parameter concatenation after the URL
RxHttp.head(String)             // Head Request parameters are concatenated after the URL
RxHttp.postForm(String)         // Post request parameters are submitted in {application/x-www-form-urlencoded} form
RxHttp.postJson(String)         // Post request parameters with {application/json; Charset = UTF-8} to send a Json object
RxHttp.postJsonArray(String)    // Post request parameters with {application/json; Charset = UTF-8} and send a Json array
RxHttp.putForm(String)          // Put request parameters are submitted in {application/x-www-form-urlencoded} form
RxHttp.putJson(String)          //put the request parameter to {application/json; Charset = UTF-8} to send a Json object
RxHttp.putJsonArray(String)     //put the request parameter to {application/json; Charset = UTF-8} and send a Json array
RxHttp.patchForm(String)        // Patch request parameters are submitted in {application/x-www-form-urlencoded} form
RxHttp.patchJson(String)        // Set the patch request parameter to {application/json; Charset = UTF-8} to send a Json object
RxHttp.patchJsonArray(String)   // Set the patch request parameter to {application/json; Charset = UTF-8} and send a Json array
RxHttp.deleteForm(String)       // Delete request parameters are submitted in {application/x-www-form-urlencoded} form
RxHttp.deleteJson(String)       // Delete request parameters with {application/json; Charset = UTF-8} to send a Json object
RxHttp.deleteJsonArray(String)  // Delete request parameters with {application/json; Charset = UTF-8} and send a Json array
Copy the code

You will find that there are actually 6 types of the above 14 request methods, corresponding to the methods of Get, Head, Post, Put, Patch and Delete, but there are 3 methods of Post, Put, Patch and Delete each with different forms of submission, you only need to choose according to your own requirements.

If the above method does not satisfy your needs, we can also customize the request method through the @param annotation, the use of which will be discussed in more detail later in this article.

Note: When calling xxxForm method to send a request, setMultiForm() method or calling addFile(String, File) to add a File, the internal parameters will automatically be submitted in {multipart/form-data} mode

Add parameters/headers

After determining the request method, we can call a series of addXxx() methods to add parameters/request headers, as follows:

RxHttp.get("/service/...")       // Send a GET request
    .add("key"."value")         // Add parameters
    .addAll(new HashMap<>())     // Add multiple parameters via Map
    .addHeader("deviceType"."android")     // Add the request header.Copy the code

All three methods can be called to add parameters/request headers for any request. Of course, there are different addXxx methods for developers to call for different requests. As follows:

// There will be more addAll methods to call in the postJson request method
RxHttp.postJson("/service/...") // Send a POST Json request
    .addAll(new JsonObject())   // Add multiple parameters through the JSON object
    .addAll("{\"height\":180,\"weight\":70}") // Add multiple arguments via a JSON string.// The postForm request method will have a series of addFile methods to call
RxHttp.postForm("/service/...")  // Send a post form request
    .addFile("file".new File("xxx/1.png")) // Add a single file
    .addFile("fileList".new ArrayList<>()) // Add multiple files.Copy the code

The above lists only a few common addXxx methods, more methods please download the source code experience.

Part 2: Determining return Data Types

For example, if we want to return a Student object, we can use the asClass(Class

) method as follows:

RxHttp.postForm("/service/...")  // Send a post form request
    .add("key"."value")         // Add parameters that can be called multiple times
    .asClass(Student.class)    // Return the Student type
    .subscribe(student -> {   
        // If the request succeeds, the Student object will be available
    }, throwable -> {         
        // The request failed
    });    
Copy the code

To return a list of Student objects, use the asList(Class

) method as follows:

RxHttp.postForm("/service/...")  // Send a post form request
    .add("key"."value")         // Add parameters that can be called multiple times
    .asList(Student.class)       // Return type List
      
    .subscribe(students -> {   
        // The request succeeds, and we get the list of Student objects
    }, throwable -> {         
        // The request failed
    });    
Copy the code

parsingResponse<T>Type data

However, in real world development, most people’s interfaces return data structures that look something like this

public class Response<T> {
    private int    code;
    private String msg;
    private T      data;
    // Omit the get and set methods
}
Copy the code

For this data structure, according to the traditional writing method, every time to make a judgment on the code, if there are 100 requests, to judge 100 times, really will be obsessive compulsive.

In this case, RxHttp gives a perfect answer. For example, if the T in Response

represents a Student object, it can be obtained by asResponse(Class

), as follows:

RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponse(Student.class)    // Return the Student type
    .subscribe(student -> {   
        // The request succeeds, and the Student object is available
    }, throwable -> {         
        // The request failed
    });    
Copy the code

If the T in Response

represents a List

List object, it can be obtained via the asResponseList(Class

) method, as shown below

RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponseList(Student.class)    // Return type List
      
    .subscribe(students -> {   
        // The request succeeds, and the List
      
        object is available
      
    }, throwable -> {         
        // The request failed
    });    
Copy the code

More often than not, our list data is paging, like the data structure below

{
    "code": 0."msg": ""."data": {
        "totalPage": 0."list": []}}Copy the code

In this case, call RxHttp asResponsePageList(Class

) method can still be perfectly solved, as follows:

RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponsePageList(Student.class)    // Return the PageList
      
        type
      
    .subscribe(pageList -> {   
        // The request is successful, so we can get the PageList
      
        list object
      
       int totalPage = pageList.getTotalPage();   / / the total number of pages
       List<Student> students = pageList.getData();  // Single-page list data
    }, throwable -> {         
        // The request failed
    });    
Copy the code

At this point, a lot of people are going to ask me,

  • Where is your code judged?
  • If my code is 100 or some other value, it is correct. How to change it?
  • myResponse<T>Class inside the field name, and yours are different, how should?
  • Go straight back when you’re successfulResponse<T>T, then I need to get the code to make other judgments and execute different business logic. What should I do?

AsResponse (Class

), asResponseList(Class

), and asResponsePageList(Class

) are not provided by RxHttp. The code judgment and Response

classes are all customized by the developer. For details on how to customize the Parser, see section 5.1 —- Customizing The Parser.

Then answer the fourth question, how to get the code to make other business logic judgment, very simple, we only need to use the OnError interface to handle the error callback, as follows:

RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponse(Student.class)    // Return the Student type
    .subscribe(student -> {   
        // The request succeeds, and the Student object is available
    }, (OnError) error -> {     // Note that we use the OnError interface, where error is an ErrorInfo object
        // Fail callback
        // Obtain the code field. At this time, you can make a judgment on the code and execute different business logic
        int code = error.getErrorCode();     
        String errorMsg = error.getErrorMsg()  // Get the MSG field
    });    
Copy the code

Note: The OnError interface above is not provided internally by RxHttp, but is a custom interface that can be found in Demo

The above five asXxx methods can be said to cover more than 80% of business scenarios. Next, let’s take a look at the asXxx methods provided by RxHttp, as follows:RxHttp is provided internally23aasXXXMethods, in which:

  • There are seven wrapper types that return basic types, such as asInteger, asBoolean, asLong, and so on.
  • Seven more are return object types, such as asString, asBitmap, asList, asMap(three), and the most commonly usedasClassMethods;
  • The remaining 9 areasParser(Parser<T>),asUploadSeries method andasDownloadSeries of methods.

Duang, duang, duang!! To highlight, I can tell you that in fact, the previous 14 methods are finally implemented by asParser(Parser

) method. The specific implementation process will be skipped here and explained in detail later.

3.3.3 Trilogy: Subscription callbacks

In part 2, the asXxx method returns an Observable

object. Yes, it is an Observable

object inside RxJava. In this case, we can subscribe to the callback using the subscribe series method, as follows:

// No callbacks are processed
RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponseList(Student.class)    // Return type List
      
    .subscribe();    // Do not subscribe to any callbacks
    
// Only subscribe to the successful callback
RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponseList(Student.class)    // Return type List
      
    .subscribe(students -> {   
        // The request succeeds, and the List
      
        object is available
      
    });    
    
// Subscription success and failure callbacks
RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponseList(Student.class)    // Return type List
      
    .subscribe(students -> {   
        // The request succeeds, and the List
      
        object is available
      
    }, throwable -> {         
        // The request failed
    });
    
// And so on, omit
Copy the code

In addition, we can subscribe to request start/end callbacks as follows:

RxHttp.get("/service/...")
    .asString()
    .observeOn(AndroidSchedulers.mainThread())
    .doOnSubscribe(disposable -> {
        // The request starts, currently in the main thread callback
    })
    .doFinally(() -> {
        // The request is finished, and the current callback is in the main thread
    })
    .as(RxLife.as(this))  // Perceive the life cycle
    .subscribe(s -> {
        // Successful callback, currently in the main thread callback
    }, (OnError) error -> {
        // Failure callback, currently in the main thread callback
    });
Copy the code

At this point, the request trilogy is over, and we’ll move on to other commonly used features

3.4. Initialization

// Set debug mode. The default value is false. If this parameter is set to true, you can filter "RxHttp" to see the request log
RxHttp.setDebug(boolean debug)
// This is not required. It can only be initialized once. The second time will throw an exception
RxHttp.init(OkHttpClient okHttpClient)
// Alternatively, there will be log output in debug mode
RxHttp.init(OkHttpClient okHttpClient, boolean debug)
Copy the code

This step is optional. If you need to add interceptors or other business requirements, you can call the init method to initialize. If you do not initialize or pass null, the default OkHttpClient object will be used. The default OkHttpClient object can be found in the HttpSender class, as follows:

private static OkHttpClient getDefaultOkHttpClient(a) {                              
    X509TrustManager trustAllCert = new X509TrustManagerImpl();                     
    SSLSocketFactory sslSocketFactory = new SSLSocketFactoryImpl(trustAllCert);     
    return new OkHttpClient.Builder()                                               
        .connectTimeout(10, TimeUnit.SECONDS)                                       
        .readTimeout(10, TimeUnit.SECONDS)                                          
        .writeTimeout(10, TimeUnit.SECONDS)                                         
        .sslSocketFactory(sslSocketFactory, trustAllCert) // Add a trust certificate
        .hostnameVerifier((hostname, session) -> true) // Ignore host authentication
        .build();                                                                   
}                                                                                   
Copy the code

Although initialization is not required, it is recommended that you pass in a custom OkHttpClient object. First, the custom OkHttpClient can maximize the satisfaction of their own business; Second, as the RxHttp version is upgraded, the default OkHttpClient may change (although very unlikely), so it is recommended to customize the OkHttpClient object into RxHttp.

3.5. Public parameters/headers

RxHttp supports adding public parameters/headers for all requests, and of course, if you want a request to have no public parameters/headers, it is also supported, and it is very simple. As follows:

RxHttp.setOnParamAssembly(new Function() {
    @Override
    public Param apply(Param p) { // This method is executed in a child thread, that is, the thread that initiated the request
        Method method = p.getMethod();
        if (method.isGet()) {     // Different parameters can be added depending on the type of request
        } else if (method.isPost()) {
        }
        return p.add("versionName"."1.0.0")// Add public parameters
                .addHeader("deviceType"."android"); // Add a common request header}});Copy the code

. We need to call RxHttp setOnParamAssembly (Function) method, and pass in a Function interface object, every time a request, will callback that interface.

Of course, if you want a request to not call back to this interface, that is, not add a public argument/request header, you can call the setAssemblyEnabled(Boolean) method with false, as follows:

RxHttp.get("/service/...")       / / get request
    .setAssemblyEnabled(false)   // Set whether to add public arguments/headers. Default is true
    .asString()                  // Return string data
    .subscribe(s -> {            // The s type is String
        // The request succeeded
    }, throwable -> {                                  
        // The request failed
    });                                                
Copy the code

3.6. Multiple or dynamic domain names

3.6.1. Multiple domains

RxHttp provides @defaultdomain () and @domain () annotations to indicate the DefaultDomain name and non-default Domain name, as follows:

public class Url {
    @DefaultDomain() // Set this to the default domain name
    public static String baseUrl = "https://www.wanandroid.com/"
    
    @Domain(name = "BaseUrlBaidu") // Non-default domain name and alias BaseUrlBaidu
    public static String baidu = "https://www.baidu.com/";
    
    @Domain(name = "BaseUrlGoogle") // Non-default domain name and alias BaseUrlGoogle
    public static String google = "https://www.google.com/";
}
Copy the code

Annotating a non-default Domain name with the @domain () annotation generates the setDomainToXxxIfAbsent() method in the RxHttp class, where Xxx is the alias taken in the annotation.

We used two @domain () annotations, At this time (need to Rebuild project) will generate setDomainToBaseUrlBaiduIfAbsent in RxHttp class (), setDomainToBaseUrlGoogleIfAbsent () these two methods, send the request at this time, We can use the specified domain name, as follows:

// Use the default domain name without adding any additional code
/ / at this point the url = "https://www.wanandroid.com/service/..."
RxHttp.get("/service/...")
    .asString()  
    .subscribe();
    
/ / manually enter the domain name, url = "https://www.mi.com/service/..."
RxHttp.get("https://www.mi.com/service/...")
    .asString()  
    .subscribe();

// If you specify the domain name again when you enter the domain name manually, it is invalid
/ / at this point the url = "https://www.mi.com/service/..."
RxHttp.get("https://www.mi.com/service/...")
    .setDomainToBaseUrlBaiduIfAbsent()  // The specified Baidu domain name is invalid
    .asString()  
    .subscribe();
    
/ / use Google domain name, the url = "https://www.google.com/service/..."
RxHttp.get("/service/...")
    .setDomainToBaseUrlGoogleIfAbsent() // Specify the Google domain name
    .asString()  
    .subscribe();
Copy the code

The preceding example shows that there are three ways to specify a domain name in RxHttp: Manually enter the domain name, specify a non-default domain name, and use the default domain name in order of priority.

3.6.2. Dynamic Domain name

In real development, there will also be dynamic domain name switching requirements, such as domain name sealing, or need to be configured according to the domain name delivered by the server, this is so easy for RxHttp!! We just need to reassign BaseUrl, and the request will take effect immediately, as follows:

/ / at this point the url = "https://www.wanandroid.com/service/..."
RxHttp.get("/service/...")
    .asString()  
    .subscribe();
    
Url.baseUrl = "https://www.qq.com"; // Dynamic change of the default domain name takes effect immediately. The same is true for non-default domain name
/ / at this point the url = "https://www.qq.com/service/..."
RxHttp.get("/service/...")
    .asString()  
    .subscribe();
Copy the code

Close the request

RxHttp provides two ways to close the request, which are automatic and manual. If the request is not finished when the page is destroyed, there will be a danger of memory leak.

3.7.1 Automatic close request

To automatically close requests, we need to introduce my open source library RxLife, so let’s see how to use it:

// The following code is called in FragmentActivty/Fragment

RxHttp.postForm("/service/...")
    .asString()
    .as(RxLife.as(this)) // Page destruction, automatic close request
    .subscribe();
    / / or
RxHttp.postForm("/service/...")
    .asString()
    .as(RxLife.asOnMain(this)) // The page destroys, automatically closes the request and calls back the observer on the main thread
    .subscribe();

// Kotlin user, please use the life or lifeOnMain method, as follows:
RxHttp.postForm("/service/...")
    .asString()
    .life(this) // Page destruction, automatic close request
    .subscribe();
    / / or
RxHttp.postForm("/service/...")
    .asString()
    .lifeOnMain(this) // The page destroys, automatically closes the request and calls back the observer on the main thread
    .subscribe();
Copy the code

Above this as LifecycleOwner interface object, our FragmentActivity/fragments are implements this interface, all we can directly in the FragmentActivity/fragments pass this. For those who are not familiar with RxLife, check out the most elegant management RxJava lifecycle in RxLife history, which is not covered in detail here.

3.7.2 Manually Closing requests

To close the request manually, we only need to get the Disposable object at the time of the subscription callback, through which we can judge whether the request is finished. If not, we can close the request as follows:

// Subscribe callback to get the Disposable object
Disposable disposable = RxHttp.get("/service/...")
    .asString()  
    .subscribe(s -> { 
       // Successful callback
    }, throwable -> {
       // Fail callback
    });
    
if(! disposable.isDisposed()) {// Determine if the request has ended
    disposable.dispose();       // If there is no end, the request is closed
}                              
Copy the code

3.8. File upload/download/Progress Monitoring

RxHttp can be very elegant to implement upload/download and progress monitoring, is a mule or a horse, pull out of the walk

3.8.1 upload

Add files using the addFile series method as follows:

RxHttp.postForm("/service/...") // Send a Post request in the Form Form
    .addFile("file1".new File("xxx/1.png"))  // Add a single file
    .addFile("fileList".new ArrayList<>())   // Add multiple files via the List object
    .asString()                                      
    .subscribe(s -> {                              
        // Upload succeeded
    }, throwable -> {                              
        // Failed to upload
    });                                            
Copy the code

Monitor the upload progress through the upload series method, as follows:

RxHttp.postForm("/service/...") // Send a Post request in the Form Form
    .addFile("file1".new File("xxx/1.png"))                                         
    .addFile("file2".new File("xxx/2.png"))                                         
    .upload(progress -> {                                                          
        // The upload progress callback ranges from 0 to 100, only when the progress is updated
        int currentProgress = progress.getProgress(); // The current progress is 0-100
        long currentSize = progress.getCurrentSize(); // The size of the current uploaded bytes
        long totalSize = progress.getTotalSize();     // Total size of bytes to upload
    }, AndroidSchedulers.mainThread())   // Specify the callback (progress/success/failure) thread, do not specify, default in the request thread callback
    .asString()                                       
    .subscribe(s -> {                                                                
        // Upload succeeded
    }, throwable -> {                                                                
        // Failed to upload
    });                                                                              
Copy the code

As you can see, we simply replace the asString() method with the asUpload(Consumer, Scheduler) method. The first argument is the progress listener interface, which is called whenever the progress is updated, and the second argument is the thread that specifies the callback. Here we specified a callback in the UI thread.

3.8.2, download

To download, use the asDownload(String) method and pass in the local path

  // File storage path
String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .asDownload(destPath) // Note that the asDownload operator is used and the local path is passed in
    .subscribe(s -> {
        // If the file is successfully downloaded, call back to the file download path
    }, throwable -> {
        // Download failed
    });
Copy the code

3.8.3 Download with progress

With progress of the download using asDownload (String, Consumer, the Scheduler) method

  // File storage path
String destPath = getExternalCacheDir() + "/" + System.currentTimeMillis() + ".apk";
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .asDownload(destPath, progress -> {
        // Download progress callback,0 to 100, only when the progress is updated, the maximum callback 101 times, the last callback file storage path
        int currentProgress = progress.getProgress(); // The current progress is 0-100
        long currentSize = progress.getCurrentSize(); // The size of the current downloaded bytes
        long totalSize = progress.getTotalSize();     // Total size of bytes to download
    }, AndroidSchedulers.mainThread()) // Specify the main thread callback
    .subscribe(s -> {// The value of s is String. Here is the file storage path
        // When the download is complete, process the related logic
    }, throwable -> {
        // Download failed, process related logic
    });
Copy the code

3.8.4 Download at Breakpoint

A breakpoint download makes no difference to a download by calling the setRangeHeader(Long startIndex, Long endIndex) method and passing in the start and end positions (the end position is not passed by default to the end of the file)

String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
long length = new File(destPath).length(); // The length of the downloaded file
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .setRangeHeader(length)  // Set the start location of the download. The end location defaults to the end of the file
    .asDownload(destPath)
    .subscribe(s -> { // The s type is String
        // Download successfully, process related logic
    }, throwable -> {
        // Download failed, process related logic
    });
Copy the code

3.8.5 Download with Progress breakpoint

A download with progress breakpoint makes no difference to a download with progress by simply calling the setRangeHeader method and passing in the start and end locations (the end location is not passed by default to the end of the file)

String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
long length = new File(destPath).length(); // The length of the downloaded file
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .setRangeHeader(length)  // Set the start location of the download. The end location defaults to the end of the file
    .asDownload(destPath, progress -> {
        // Download progress callbacks, ranging from 0 to 100, will only be called when progress is updated
        int currentProgress = progress.getProgress(); // The current progress is 0-100
        long currentSize = progress.getCurrentSize(); // The size of the current downloaded bytes
        long totalSize = progress.getTotalSize();     // Total size of bytes to download
    }, AndroidSchedulers.mainThread()) // Specify the main thread callback
    .subscribe(s -> { // The s type is String
        // Download successfully, process related logic
    }, throwable -> {
        // Download failed, process related logic
    });
Copy the code

Note: In the download with the progress breakpoint above, the return progress will start from 0. If you need to connect the progress of the last download, Call ‘setRangeHeader(Long startIndex, Long endIndex, Boolean connectLastProgress)’ and pass true to the third argument. The default is false, as follows:

String destPath = getExternalCacheDir() + "/" + "Miaobo.apk";
long length = new File(destPath).length(); // The length of the downloaded file
RxHttp.get("http://update.9158.com/miaolive/Miaolive.apk")
    .setRangeHeader(length, true)  // Set the start location of the download. The end location defaults to the end of the file
    .asDownload(destPath, progress -> {
        // Download progress callbacks, ranging from 0 to 100, will only be called when progress is updated
        int currentProgress = progress.getProgress(); // The current progress is 0-100
        long currentSize = progress.getCurrentSize(); // The size of the current downloaded bytes
        long totalSize = progress.getTotalSize();     // Total size of bytes to download
    }, AndroidSchedulers.mainThread()) // Specify the main thread callback
    .subscribe(s -> { // The s type is String
        // Download successfully, process related logic
    }, throwable -> {
        // Download failed, process related logic
    });
Copy the code

3.9 Setting timeout

3.9.1 Setting global Timeout

The default read, write, and connection timeout duration of RxHttp is 10s. To change the timeout duration, customize the OkHttpClient object as follows:

// Set the read, write, and connection timeout period to 15s
OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(15, TimeUnit.SECONDS)
    .readTimeout(15, TimeUnit.SECONDS)
    .writeTimeout(15, TimeUnit.SECONDS)
    .build();
RxHttp.init(client);
Copy the code

3.9.2 Setting timeout for a single request

To set a timeout for a single request, use the RxJava timeout(long Timeout, TimeUnit TimeUnit) method as follows:

RxHttp.get("/service/...")
    .asString()
    .timeout(5, TimeUnit.SECONDS)// Set the total timeout period to 5s
    .as(RxLife.asOnMain(this))  // Perceive the life cycle and call back on the main thread
    .subscribe(s -> {
        // Successful callback
    }, (OnError) error -> {
        // Fail callback
    });
Copy the code

Note: The total timeout period must be less than the sum of global read, write, and connection timeout periods. Otherwise, it is invalid

3.10. Set up Converter

3.10.1. Set global Converter

IConverter converter = FastJsonConverter.create();
RxHttp.setConverter(converter)
Copy the code

Set up a separate Converter for the request

First, you need to declare Converter in any public class using the @Converter annotation, as follows:

public class RxHttpManager {
    @Converter(name = "XmlConverter") // Specify the name of the Converter
    public static IConverter xmlConverter = XmlConverter.create();
}
Copy the code

Then rebuild the project and you automatically generate the setXmlConverter() method in the RxHttp class. You can then call this method to specify the Converter for a single request, as follows:

RxHttp.get("/service/...")
    .setXmlConverter()   // Specifies to use XmlConverter. If not, the global Converter is used
    .asClass(NewsDataXml.class)
    .as(RxLife.asOnMain(this))  // Perceive the life cycle and call back on the main thread
    .subscribe(dataXml -> {
        // Successful callback
    }, (OnError) error -> {
        // Fail callback
    });
Copy the code

3.11 request encryption and decryption

3.11.1, encryption,

To request encryption, you need a custom Param, very simple, see section 5.2 of this article —- Custom Param for details

3.11.2, decrypt

Sometimes, the request returns a long string of ciphertext. In this case, you need to convert the ciphertext to plain text.

// Set data decryption/decoder
RxHttp.setResultDecoder(new Function<String, String>() {
    // Each time the request succeeds, this is called back, passing in the ciphertext returned by the request
    @Override                                              
    public String apply(String s) throws Exception {   
        String plaintext = decode(s);   // Decrypt the ciphertext into plain text, the decryption logic itself
        return plaintext;    // Return plaintext}});Copy the code

SetResultDecoder (Function

) is a static method called RxHttp. SetResultDecoder (Function

) is a static method called RxHttp. SetResultDecoder (Function

) is a static method called RxHttp.
,>
,>
,>

However, for some requests that do not require decrypting, call the setDecoderEnabled(Boolean) method and pass false, as follows:

RxHttp.get("/service/...")
    .setDecoderEnabled(false)  // This request does not require decryption. Default is true
    .asString()
    .subscribe(s -> {
        // Successful callback
    }, (OnError) error -> {
        // Fail callback
    });
Copy the code

3.12. Synchronize the request/specify callback thread

RxHttp executes the request in the Io thread by default, and it also executes the callback in the Io thread by default. By default, the request is executed in the same Io thread and the callback is called.

3.12.1 Synchronous request

By default, RxHttp initiates requests in the IO thread, i.e. asynchronous requests. If you need to synchronize a request, call setSync, as follows:

// Specify the thread in which the request is to be called. It needs to be called anywhere before the second part of the curve, but not after the second part
RxHttp.get("/service/...")
    .setSync() // Execute synchronously,
    .asString()  
    .subscribe();
Copy the code

The above use of RxJava thread scheduler, unfamiliar please consult the relevant information, here do not do a detailed introduction.

3.12.2. Specify the thread on which the callback resides

Specify the thread on which the callback is to be called, and still use RxJava’s thread scheduler, as follows:

// Specify the thread on which the callback is to be called after part 2
RxHttp.get("/service/...")
    .asString()  
    .observeOn(AndroidSchedulers.mainThread()) // Specify callback on the main thread
    .subscribe(s -> { // S is a String, and the main thread calls back
        // Successful callback
    }, throwable -> {
        // Fail callback
    });
Copy the code

3.13 Retrofit users

I’m a Retrofit user who likes to write the interface in a class and then call it directly. How to implement RxHttp? The asXxx method returns an Observable

object, so we can do this:

public class HttpWrapper {

    public static Observable<List<Student>> getStudent(int page) {
        return RxHttp.get("/service/...")
            .add("page", page) .asList(Student.class); }}// Then it can be called directly from elsewhere
HttpWrapper.getStudent(1)
    .as(RxLife.asOnMain(this))  // Callback to the main thread and destroy the auto-close request on the page (if not already closed)
    .subscribe(students -> { // Student list
        // Successful callback
    }, throwable -> {
        // Fail callback
    });
Copy the code

Return an Observable

object when wrapping.

Another student asked, we get the list interface, page number is spliced together with the URL, Retrofit can be through a placeholder, how about RxHttp? Simple, as follows:

public class HttpWrapper {

    // A single placeholder
    public static Observable<Student> getStudent(int page) {
        return RxHttp.get("/service/%d/...", page)  // Use the standard placeholder protocol
            .asClass(Student.class);
    }
    
    // Multiple placeholders
    public static Observable<Student> getStudent(int page, int count) {
        return RxHttp.get("/service/%1$d/%2$d/...", page, count)  // Use the standard placeholder protocol.asClass(Student.class); }}Copy the code

This is different from Retrofit, which uses annotations to specify placeholders, whereas RxHttp uses standard placeholders. We just declare them in the URL and pass in the corresponding parameters after the URL.

4. Principle analysis

RxHttp uses the popular Annotation Processing Tool (APT), Libraries such as Eventbus, ButterKnife, Dagger2, Glide, and Jetpack are very useful Room database frameworks that use APT to retrieve annotation information at compile time. Generate Java classes, methods, and other related code through the Javapoet framework (to generate Kotlin-related code, use KotlinPoet) and thus achieve zero performance cost at run time.

So, what advantages does APT bring to RxHttp? How does RxHttp use APT? Keep reading

When we talk about APT, the first thing that comes to mind is probably decoupling. Yes, decoupling is one of its advantages. In fact, it has an even greater advantage, that is, generating different code logic based on configuration. In RxHttp, for example, the default is not dependent on RxJava, but if you need to use RxHttp + RxJava way to send a request, can be in annotationProcessorOptions label rxhttp_rxjava parameters to configure RxJava version, Can be passed RxJava2 or RxJava3, internal according to the passed RxJava version, generate different code, so that you can do a set of code simultaneously and through RxJava2 and RxJava3, if the subsequent out of the RxJava4, RxJava5 and other new versions, the same can be compatible, and very simple.

For this purpose, RxHttp ADAPTS any version of OkHttp v3.12.0 to V4.9.0 (the latest version as of 2020/12/27) (except v4.3.0). There is a bug in this version that makes it uncompatible), so with RxHttp, you don’t have to worry about okHTTP version conflicts at all.

The first advantage APT brings to RxHttp is that it is compatible with different versions of RxJava and OkHttp.

How does RxHttp use APT? In RxHttp, a total of six annotations are defined, as follows:

  • @defaultDomain: Use this to specify the default baseUrl, which can only be used once

  • @domain: Specifies a non-default baseUrl, which can be used multiple times

  • @parser: Specifies a custom Parser that can be used multiple times. This is very powerful. You can write your own data parsing logic in the Parser and return any type of data, which perfectly solves the problem of irregular data returned by the server

  • @param: Specifies a custom Param that can be used multiple times when sending unified encryption requests

  • OkClient: Configure different OkHttpClient objects for different requests, which can be used multiple times

  • @Converter: Configure different Converter objects for different requests and can be used multiple times

Note: Please see how the above six notes are usedRxHttp annotations are used

The RxHttp annotation processor is called the RXHTTP-Compiler. Its primary task is to generate the RxHttp class. The second task is to retrieve the above six annotations and generate the corresponding classes and methods. You can directly use the @param annotation generated method, as follows:

// Send an encrypted post form request with a method name optionally specified via the @param annotation
val student = RxHttp.postEncryptForm("/service/...")
    .add("key"."value")
    .toClass<Student>()
    .await()
Copy the code

The advantages of the other five annotations will not be explained in detail, but the other big advantage is decoupling so that any request follows the request trilogy

RxHttp workflow

Next, looking at the RxHttp workflow, there are five important roles, which are:

  • RxHttp: This is the most important role, so the only entry point to the Request, internally holds a Param object, which is responsible for processing Request parameters/headers /BaseUrl, scheduling Request threads, providing annotation generation methods, etc., and ultimately building an okHttp3.request object through Param. Then build an OkHttp3.Call object and throw the Call object to an Observable or IAwait that actually executes the request

  • Param: Its job is to handle the Request parameters/Request headers/URLS and everything else needed to build the okHttp3.request object. Its final job is to build the okHttp3.request object, which is held by the RxHttp class. RxHttp builds the okHttp3.request object. It’s all up to Param

  • IAwiat: The object that actually executes the network request when the request is sent in combination with the coroutine. The specific implementation class is AwaitImpl, which holds the Parser object inside. After the request is returned, okHttp3. Response is thrown to the Parser for parsing and the parsed object is returned

  • Observables. When RxJava sends a request, the object that actually executes the network request is implemented by ObservableCallExecute, ObservableCallEnqueue, ObservableParser, It is used to parse data from the OkHttp3. Response object for synchronous request, asynchronous request, and return request, respectively. The ObservableParser holds the Parser object internally, and the detailed parsing work is given to the Parser

  • Parser: Parses the data to the desired data type, which is an interface object with only onParse(Response: response) inside: The method T has four specific implementation classes: SimpleParser, StreamParser, SuspendStreamParser and BitmapParser. The first is a universal parser, and the internal asClass/toClss method is implemented through it. The second and third is to download the file when using the parser, the difference between the former is combined with RxJava download, the latter is combined with coroutine download; The last one is used to resolve Bitmap objects, such as asBitmap/toBitmap

Work flow chart is as follows:

5, extension,

5.1. Customize the Parser

In part 2 of the previous series, we introduced a series of asXxx methods that conveniently specify the data return type, AsResponse (Class

), asResponseList(Class

), asResponsePageList(Class

). Let’s take a look at how to customize a Parser.

The source code is always the best way to learn, but before we start looking at custom Parsers, how do we implement the built-in Parser

SimPleParser

public class SimpleParser<T> extends AbstractParser<T> {

    // Omit the constructor
    @Override
    public T onParse(Response response) throws IOException {
        returnconvert(response, mType); }}Copy the code

As you can see, in addition to the constructor of SimpleParser, there is only one onParser method, which is defined in the Parser interface, and the implementation of convert(Response, Type), which is also defined in the Parser interface and has a default implementation. As follows:

public interface Parser<T> {

    // Input Response and output T
    T onParse(@NonNull Response response) throws IOException;

    // Convert the result returned by Http to the expected entity class object
    default <R> R convert(Response response, Type type) throws IOException {
        ResponseBody body = ExceptionHelper.throwIfFatal(response);  / / here inside make code < 200 | | code > = 300, throw an exception
        boolean onResultDecoder = isOnResultDecoder(response); // Whether to decrypt the returned data
        LogUtil.log(response, onResultDecoder, null);
        IConverter converter = getConverter(response);        // Remove the converter
        return converter.convert(body, type, onResultDecoder); // Convert data into play
    }
    // Omit several methods
}
Copy the code

As you can see, it’s very simple. We input the Response object and the generic Type Type, which is internally converted through the IConverter interface to the entity class object we expect and returned.

To customize a Parser, you need to inherit AbstractParser and then implement the onParser method. Let’s see if this is what the built-in ListParser does:

public class ListParser<T> extends AbstractParser<List<T>> {

    // Omit the constructor
    @Override
    public List<T> onParse(Response response) throws IOException {
        final Type type = ParameterizedTypeImpl.get(List.class, mType); // Get the generic type
        returnconvert(response, type); }}Copy the code

As you can see, this is almost the same implementation as the SimpleParser parser, except that here we combine the generic T we input with the List into a new generic type and return the List

object.

Now we can define the ResponseParser to handle the Response

data type, and look at the data structure:

public class Response<T> {
    private int    code;
    private String msg;
    private T      data;
    // Omit the get and set methods
}
Copy the code

The custom ResponseParser code looks like this:

@Parser(name = "Response", wrappers = {List.class, PageList.class})
public class ResponseParser<T> extends AbstractParser<T> {

    // Note that the following two constructors are required
    protected ResponseParser(a) { super(a); }public ResponseParser(Type type) { super(type); }

    @Override
    public T onParse(okhttp3.Response response) throws IOException {
        final Type type = ParameterizedTypeImpl.get(Response.class, mType); // Get the generic type
        Response<T> data = convert(response, type);
        T t = data.getData(); // Get the data field
        if(data.getCode() ! =200 || t == null) {// If code is not equal to 200, the data is incorrect and an exception is thrown
            throw new ParseException(String.valueOf(data.getCode()), data.getMsg(), response);
        }
        returnt; }}Copy the code

Two things need to be noted in the above code

First, we start the class with the @parser annotation, which takes two arguments, as follows:

  • RxHttp Class asResponse(Class

    ) method (named as + name attribute value);

  • Wrappers can interpret this as a wrapper Class for the generic T. We need to pass in the Class[] array object. Here we pass in {list.class, pagelist.class}. The asResponseList(Class

    ) and asResponsePageList(Class

    ) methods are generated. (Named as: as +name attribute value +Class Class name)

Note: The PageList class needs to be defined to load paging data and is available in Demo

Second, in the if statement, we make a judgment that code is not 200 or data is null, and we throw an exception with the code and MSG fields, so we get those two fields in the exception callback

List

, PageList

, List

, PageList

// In the first way, @parser is used to annotate the generated asResponse method
RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asResponse(Student.class)           // Return the Student type
    //.asresponselist (student.class) // Returns the List
      
        type
      
    //.asresponsepagelist (student.class) // Returns the PageList
      
        type
      
    .subscribe(student -> {   
        // The request succeeds, and the Student object is available
    }, throwable -> {         
        // The request failed
    });   

// In the second way, use the asParser(Parser
      
       ) method
      
RxHttp.postForm("/service/...")   // Send a post form request
    .add("key"."value")          // Add parameters that can be called multiple times
    .asParser(new ResponseParser<Student>(){})    // Return the Student type
    .subscribe(student -> {   
        // The request succeeds, and the Student object is available
    }, throwable -> {         
        // The request failed
    });  
Copy the code

The above two methods are the same except for the differences in writing methods. I believe that everyone will choose the first way, which is not only simple to write, but also reduces the coupling.

5.2. Customize Param

Customizing Param is much simpler than customizing Parser. We only need to add or rewrite methods based on our own needs by inheriting NoBodyParam, FormParam, JsonParam, etc. For example, we need to customize Param in the following three cases:

  • The postForm request requires all the added parameters to be stitched together, then encrypted, and finally the encrypted string added to the request header
  • For a postJson request, all parameters, i.e., json strings, need to be encrypted before being sent
  • I don’t have enough apis in FormParam, so I have to customize the API

5.2.1 postForm request encryption

In this case, we need to inherit from FormParam and override the getRequestBody() method as follows:

@Param(methodName = "postEncryptForm")
public class PostEncryptFormParam extends FormParam {

    public PostEncryptFormParam(String url) {
        super(url, Method.POST);  //Method.POST indicates the POST request
    }

    @Override
    public RequestBody getRequestBody(a) {
        // Get all the parameters you added here
        List<KeyValuePair> keyValuePairs = getKeyValuePairs();
        String encryptStr = "Encrypted string";  // Implement the encryption logic based on the above parameters
        addHeader("encryptStr", encryptStr);
        return super.getRequestBody(); }}Copy the code

5.2.2. Encrypt postJson requests

In this case, we need to inherit from JsonParam and also override the getRequestBody() method, as follows:

@Param(methodName = "postEncryptJson")
public class PostEncryptJsonParam extends JsonParam {

    public PostEncryptJsonParam(String url) {
        super(url, Method.POST);
    }

    @Override
    public RequestBody getRequestBody(a) {
        // Get all the parameters you added here
        Map<String, Object> params = getParams();
        String encryptStr = "Encrypted string";  // Implement the decryption logic based on the above parameters
        return RequestBody.create(MEDIA_TYPE_JSON, encryptStr);  // Send the encrypted string}}Copy the code

5.2.3 Custom API

We inherit FormParam and add two test methods, as follows:

@Param(methodName = "postTestForm")
public class PostTestFormParam extends FormParam {

    public PostTestFormParam(String url) {
        super(url, Method.POST);
    }
    
    public PostTestFormParam test(long a, float b) {
        // The business logic is self-fulfilling
        return this;
    }
    
    public PostTestFormParam test1(String s, double b) {
        // The business logic is self-fulfilling
        return this; }}Copy the code

5.2.4. Use custom Param

Same question, how do we use these 3 custom Param? I think most people find the @param annotation in front of the class name and give Param an alias. So what does this do? If you use the @param annotation on your custom Param, you will automatically generate a method in the RxHttp class that acts as an alias. PostEncryptForm, postEncryptJson, postTestForm, PostEncryptForm (String), postEncryptJson(String), and postTestForm(String) are generated in the RxHttp class.

  public static RxHttp$PostEncryptFormParam postEncryptForm(String url) {
    return new RxHttp$PostEncryptFormParam(new PostEncryptFormParam(url));
  }
  
  public static RxHttp$PostEncryptJsonParam postEncryptJson(String url) {
    return new RxHttp$PostEncryptJsonParam(new PostEncryptJsonParam(url));
  }

  public static RxHttp$PostTestFormParam postTestForm(String url) {
    return new RxHttp$PostTestFormParam(new PostTestFormParam(url));
  }
Copy the code

To make a request, just call the corresponding method, such as:

// Send an encrypted postForm request
RxHttp.postEncryptForm("/service/...")   
    .add("key"."value")          // Add parameters that can be called multiple times
    .asString()                  // Mandatory String
    .subscribe(s-> {   
        // The request succeeded
    }, throwable -> {         
        // The request failed
    });  
    
// Send an encrypted postJson request
RxHttp.postEncryptJson("/service/...")   
    .add("key"."value")          // Add parameters that can be called multiple times
    .asString()                  // Mandatory String
    .subscribe(s-> {   
        // The request succeeded
    }, throwable -> {         
        // The request failed
    });  
Copy the code

How do I call my custom API, so easy!!!! , and can be directly invoked after selecting the corresponding request method, as follows:

// Send an encrypted postJson request
RxHttp.postTestJson("/service/...")   
    .test(100L.99.99 F)          // Call the custom API
    .test1("testKey".88.88 D)    // Call the custom API
    .add("key"."value")         // Add parameters that can be called multiple times
    .asString()                  // Mandatory String
    .subscribe(s-> {   
        // The request succeeded
    }, throwable -> {         
        // The request failed
    });  
Copy the code

5.3. Customizing Converter

RxHttp internally uses GsonConverter by default, and provides 5 additional Converters, as follows:

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

5.3.1. Customize TestConverter

Even so, RxHttp is not guaranteed to meet all business requirements. Therefore, we can choose to customize the Converter, which inherits the IConverter interface, as follows:

public class TestConverter implements IConverter {

    /** the request will be called back if it succeeds@param body             ResponseBody
     * @paramType Specifies the generic type *@paramOnResultDecoder Whether to decode/decrypt the result */
    @Override
    public <T> T convert(ResponseBody body, Type type, boolean onResultDecoder) throws IOException {
        // Implement the relevant logic
        return null;
    }

    /** * the RequestBody object will be called back before the json request. You need to create a RequestBody object based on the generic T and return */
    @Override
    public <T> RequestBody convert(T value) throws IOException {
        // Implement the relevant logic
        return null; }}Copy the code

The above two converters are implemented according to your own business requirements. RxHttp provides converters such as FastJsonConverter and SimpleXmlConverter

5.3.2 How to use Converter

See section 3.10 of this article —- to set up Converter

6. Tips

As a tip here, since sending requests using RxHttp follows the request trilogy, we can set the code template in Android Studio, as shown belowAfter setting as shown in the figure, when writing code, enter RP and the template will be automatically generated, as follows:

7, summary

Whether you are getting, Posting, encrypted requests, custom parsers, file uploads/downloads/progress monitors, etc., all follow the request trilogy. Especially for Response

type data processing, can be said to be seamless, we do not need to judge code every time, directly can get T, it is…

Finally, if you like, please give this article a thumbs-up, if you can, please also give a star, creation is not easy, grateful. 🙏 🙏 🙏