Skip to content
liujingxing edited this page Jun 26, 2024 · 83 revisions

首次集成RxHttp,却没有RxHttp这个类?

Android Studio提示找不到RxHttp类?

使用了相关注解,没生成相关方法?

集成了RxHttp,却找不到toObservableResponse(Class)方法?

关于超时问题

生成了RxHttp类,却没有toObservableXxx方法?

token过期,如何处理?

如何切换主线程

如何发送同步请求

找不到as(RxLife.as(this))方法?

显示/销毁loading弹窗

服务器返回数据不规范,导致数据解析异常

首次集成RxHttp,却没有RxHttp这个类?

@DefaultDomain@Doman@Param@Parser@OkClient@Converter

如果你使用kapt/annotationProcessor依赖rxhttp-compiler,则会在编译期间检索以上6个注解,如果一个注解都未检索到,就不会工作(ksp检索不到注解,照样工作),也就不会生成RxHttp类;

所以,如果你使用kapt依赖了rxhttp-compiler,则需要手动使用以上任一注解

注意:rxhttp-compiler只会在本Module检索注解,故请不要在A Module依赖rxhttp-compiler,却在B Module使用以上任一注解,即使A依赖B或者B依赖A

ksp、kapt、annotationProcessor 用法及区别

检查步骤如下:

  1. 检查是否有依赖rxhttp-compiler如:
//x.x.x为具体版本号
ksp/kapt/annotationProcessor 'com.github.liujingxing.rxhttp:rxhttp-compiler:x.x.x' 
  1. 检查依赖rxhttp-compiler的Module有没有使用以上任一注解,如果没有,请手动使用其中一个

  2. 如果项目集成了kotlin,请使用ksp/kapt关键字依赖注解处理器,并且要导入kotlin-kapt/ksp插件,如下:

plugins {
    // ksp/kapt choose one
    // id 'kotlin-kapt'
    id 'com.google.devtools.ksp' version 'x.x.x-x.x.x'   //x.x.x-x.x.x 为ksp版本号
}
dependencies {
   ksp/kapt 'com.github.liujingxing.rxhttp:rxhttp-compiler:x.x.x’ (x.x.x为具体版本号)
}
  1. 最后rebuild一下项目,这是必须的

经过以上步骤,就会在build文件夹下生成RxHttp类,然而,少部分人的项目会将build文件夹设置为忽略,如下:

ignore_build.png

此时项目中build文件夹下的类是无法被引用到的,需要你在上面配置中将build文件夹移除,此时项目中就可以引用到RxHttp类。

经过以上步骤后还未生成RxHttp类,请联系我。

Android Studio提示RxHttp类找不到?

首先,明确一点,该问题并不是RxHttp的问题,而是项目中其它代码存在问题,导致编译不通过,从而无法生成RxHttp类,只需要在Android studio中的错误列表中,找出罪魁祸首,把它解决即可,如下图所示:

rxhttp_not_found_case.png

使用了相关注解,没生成相关方法?

rxhttp-compiler只会在本Module检索注解,检索不到,就不会生成相关方法,故请不要在A Module依赖rxhttp-compiler,却在B Module使用注解

集成了RxHttp,却找不到toObservableResponse(Class<T>)方法?

  • 1、该方法是通过RxJava实现的,需要你依赖RxJava

  • 2、该方法是通过自定义解析器+注解在编译期间通过rxhttp-compiler自动生成的,详情查看自定义Parser

生成了RxHttp类,却没有toObservableXxx方法?

toObservableXxx方法内部是通过RxJava实现的,所以需要你单独依赖RxJava,并告知RxHttp你依赖的RxJava版本,如下:

dependencies {    
    //rxjava2   (RxJava2/Rxjava3二选一,使用toObservable系列方法时必须)
    implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'com.github.liujingxing.rxlife2:rxlife-rxjava2:2.2.2' //管理RxJava2生命周期,页面销毁,关闭请求

    //rxjava3
    implementation 'io.reactivex.rxjava3:rxjava:3.1.6'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
    implementation 'com.github.liujingxing.rxlife:rxlife-rxjava3:2.2.2' //管理RxJava3生命周期,页面销毁,关闭请求
}
通过ksp告知RxHttp你依赖的RxJava版本
ksp {
    //依赖了RxJava时,rxhttp_rxjava参数为必须,传入RxJava版本号
    arg("rxhttp_rxjava", "3.1.6") 
}
通过kapt告知RxHttp你依赖的RxJava版本
kapt {
    arguments {
        //依赖了RxJava时,rxhttp_rxjava参数为必须,传入RxJava版本号
        arg("rxhttp_rxjava", "3.1.6")  
    }
}
通过javaCompileOptions告知RxHttp你依赖的RxJava版本
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [
                    //使用toObservableXxx方法时必须,传入你依赖的RxJava版本
                    rxhttp_rxjava: '3.1.6', 
                ]
            }
        }
    }
}

注:ksp/kapt/javaCompileOptions选其一

配置好后,rebuild即可

token过期,如何处理?

token过期涉及到具体的业务逻辑,RxHttp不可能做出深度封装。但在Demo中,已经有相关案例,详细请查看TokenInterceptor类。

如何切换主线程

RxHttp默认在IO线程发请求,也默认在IO线程回调,可以通过以下两种方式将回调切换到主线程

//方式1 通过RxAndroid
RxHttp.get("/service/...")                                             
    .toObservableString()                                                        
    .observeOn(AndroidSchedulers.mainThread())  //通过RxAndroid切换主线程     
    .subscribe(s -> {                                                  
                                                                       
    }, throwable -> {                                                  
                                                                       
    });                                                                
                                                                       
//方式2,通过RxLife                                                                       
RxHttp.get("/service/...")                                             
    .toObservableString()                                                        
    .as(RxLife.asOnMain(this))  //kotlin 使用lifeOnMain(this)替代       
    .subscribe(s -> {                                                  
                                                                       
    }, throwable -> {                                                  
                                                                       
    });                                                                

第一种方式不依赖于任何环境,任何地方都可直接调用;

第二种方式依赖于FragmentActivity/Fragment/ViewMode/View等环境,既切换主线程,又可绑定当前环境生命周期,做到页面销毁,自动关闭请求

显示/销毁loading弹窗

有两种方式,如下:

//方式1 监听各个回调
RxHttp.get("/service/...")                                                     
    .toObservableString()                                                                
    .observeOn(AndroidSchedulers.mainThread())   //控制下游在主线程执行                 
    .doOnSubscribe(disposable -> {                                            
        //请求开始                                                                
    })                                                                         
    .doFinally(() -> {                                                        
        //请求结束,不管成功/失败都会回调                                                    
    })                                                                         
    .subscribe(s -> {                                                         
        //请求成功                                                                
    }, throwable -> {                                                         
        //请求失败                                                                
    });                                                                       
  
//方式2 自定义Observer对象,订阅时传入
public class LoadingObserver<T> implements Observer<T>() {                                       
     @Override                                                             
     public void onSubscribe(Disposable d) {                               
         //请求开始,显示弹窗                                                           
     }                                                                     
                                                                              
     @Override                                                             
     public void onNext(T t) {                                        
         //请求成功                                                            
     }                                                                     
                                                                              
     @Override                                                             
     public void onError(Throwable e) {                                    
         //请求失败,销毁弹窗                                                            
     }                                                                     
                                                                              
     @Override                                                             
     public void onComplete() {                                            
         //请求完成,仅在成功时才会回调 ,销毁弹窗                                                 
     }                                                                     
}                                                                           
RxHttp.get("/service/...")                                                    
    .toObservableString()                                                               
    .observeOn(AndroidSchedulers.mainThread())   //控制下游在主线程执行                 
    .subscribe(new LoadingObserver<String>());                                                                                                                                            

注: 第二种方式,onComplete回调,仅在请求成功时才会回调

服务器返回数据不规范,导致数据解析异常

服务器正常情况下返回如下格式

{"code":200,"msg":"success","data":{}}

然而在异常情况下,返回的data字段却是五花八门,如:

//data是空字符串
{"code":100,"msg":"fail","data":""}
//或者 data是详细的错误描述
{"code":100,"msg":"fail","data":"请求失败"}
//甚至 data是一个数组对象
{"code":100,"msg":"fail","data":[]}

此时,如果我们传入对象去解析data字段,必将解析失败,从而拿不到codemsg字段。

对于以上情况,我们分两种场景:

1、客户端不需要data字段

现实开发中,客户端常会遇到不需要data字段的接口,例如关注接口,不管成功/失败,我们只需要拿到code字段,给出对应的提示即可,所以此时,我们不用管服务端返回的data字段是什么样的,因为我们用不上,故我们只需要传入String类型去解析data字段即可,如下:

RxHttp.get("/service/...")                                             
    .toObservableResponse(String.class)  //传入String类型,不管服务端返回的data字段是什么类型,都不会解析失败                                            
    .subscribe(s -> {                                                  
                                                                       
    }, throwable -> {                                                  
                                                                       
    });

然而,还有一种情况,服务端可能不返回data字段,此时我们传入的String类型的data字段就会为null,而自定义解析器不允许返回null(RxJava不允许传递null值),故我们需要在解析器里做下额外的判断,如下:

    @Override
    public T onParse(okhttp3.Response response) throws IOException {
        Response<String> data = Converter.convertTo(response, Response.class, types)
        T t = data.getData();
        if (t == null && types[0] == String.class) {
            //判断我们传入的泛型是String对象,就给t赋值""字符串,确保t不为null
            t = (T) ""; 
        }
        if (data.getCode() != 200 || t == null) {
            throw new ParseException(String.valueOf(data.getCode()), data.getMsg(), response);
        }
        return t;
    }

以上代码,会在data字段为null时,判断我们传入的泛型是不是String类型,是的话,赋值空字符串,确保data不为空,这样就能确保数据正常解析。

2、客户端需要data字段

正常情况,data是一个对象,而异常情况下,服务端返回data为""或者[],这样如果我们直接用Gson一次性解析,肯定会报JsonSyntaxException异常,此时,我们只能分两步解析,如下:

    @Override
    public T onParse(okhttp3.Response response) throws IOException {
        //第一步,解析code、msg字段,把data当成String对象
        Response<String> data = Converter.convertTo(response, Response.class, String.class)
        T t = null;
        if (data.getCode() == 200) {  //假设200代表正常情况
            //第二步,取出data字段,转换成我们想要的对象
            t = GsonUtil.getObject(data.getData(), types[0]);
        }
        if (t == null && types[0] == String.class) {
            //判断我们传入的泛型是String对象,就给t赋值""字符串,确保t不为null
            t = (T) ""; 
        }
        if (data.getCode() != 200 || t == null) {
            throw new ParseException(String.valueOf(data.getCode()), data.getMsg(), response);
        }
        return t;
    }

以上代码,结合了第一种客户端不需要data字段的情况,第一步就是先解析code、msg字段,如果code正确,再去解析data字段,这样就确保解析不会抛出异常。

找不到as(RxLife.as(this))方法?

该方法RxJava2才有,RxJava3请使用to操作符替代,如:to(RxLife.to(this))to(RxLife.toMain(this))

关于超时问题

RxHttp内部并不会直接抛出超时异常,超时异常是由OkHttp抛出,RxHttp负责原样传递而已,所以,遇到超时问题,请不要怀疑是RxHttp的问题,你可根据以下规则去排查超时原因:

  • 先检查网络问题,流量、wifi都试试,还是超时,换个手机再试试
  • 使用postman等工具试试正常响应时间需要多久,如果正常响应时间都比较慢,在代码中可以适当加大超时时间,RxHttp内部默认的读、写、连接超时均为10s,如何配置超时时间,点击这样
  • 如果是下载遇到偶现超时问题,请不要在下载链接后带时间戳等动态参数(即每次发请求,key对应的参数值都不一样),因为大多数服务器都有自带缓存,如果你每次传递的参数都不一样,服务器就不会走缓存,下载可能就会很慢,从而导致超时
Clone this wiki locally