RxJava2结合Retrofit2的网络请求示例(可测公用API)

版权声明:天际流火叩响大地之门,岁月星辰刻画沧桑年轮! https://blog.csdn.net/ytfunnysite/article/details/82387975

根据前辈经验,本文依然采用金山词霸公用api进行测试

写在前边:

依赖:

implementation 'io.reactivex.rxjava2:rxjava:2.2.1'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
    implementation 'com.amitshekhar.android:rx2-android-networking:1.0.0'
    //支持把json解析成Java对象
    implementation 'com.squareup.okhttp3:okhttp:3.11.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
    implementation 'com.jakewharton:butterknife:8.4.0'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
    implementation 'org.greenrobot:eventbus:3.1.1'
    implementation 'com.android.support:multidex:1.0.3'

自定义Gradle配置

config.buildgradle

ext.versions = [
        // 本地仓库版本
        compileSdkVersion: 28,
        buildToolsVersion: "28.0.0 rc1",
        minSdkVersion    : 15,
        targetSdkVersion : 28,
        versionCode      : 1,
        versionName      : "1.0",
        supportVersion   : "27.3.0"
]
// app 相关信息总配置
ext.appConfig = [
        applicationId    : "com.app.ytf.netdemo",
        LOCALHOST_DEBUG  : "\"http://fy.iciba.com/\"",
        LOCALHOST_RELEASE: "\"http://fy.iciba.com/\"",
        DEBUGABLE        : true,
//        GETUI_APP_ID     : "PhmRY1Uy8A9VrK2L2H8Qz3",
        GETUI_APP_KEY    : "2pjtQwS6Oghremzsy8vVZE4CSLip6egajMYuUx8Vo8WvayD21ttphi5fuYiGjoaM",
//        GETUI_APP_SECRET : "ZmO60vhutt6NxMauNZJjl8",
]
ext.channel = [
        Baidu  : "Baidu",
        Xiaomi : "Xiaomi",
        Huawei : "huawei",
        Vivo   : "vivo",
        Oppo   : "oppo",
        Tencent: "tencent",
        Server : "server"
]

gradle.properties配置签名信息

org.gradle.parallel=true
KEY_ALIAS =netdemo
KEY_PASSWORD=123456
STORE_FILE= C:/Users/ytf/netdemo.jks
STORE_PASSWORD=123456

app下build.gradle引入依赖:

apply plugin: 'com.android.application'
apply from:"$rootDir/config.gradle"

android {
    signingConfigs {
        debug {
//            keyAlias KEY_ALIAS
//            keyPassword KEY_PASSWORD
//            storeFile file(STORE_FILE)
//            storePassword STORE_PASSWORD
        }
        release {
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
            storeFile file(STORE_FILE)
            storePassword STORE_PASSWORD
        }
    }
    compileSdkVersion versions.compileSdkVersion
    buildToolsVersion versions.buildToolsVersion
    defaultConfig {
        applicationId appConfig.applicationId
        minSdkVersion versions.minSdkVersion
        targetSdkVersion versions.targetSdkVersion
        versionCode versions.versionCode
        versionName versions.versionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }
    buildTypes {
        release {
            buildConfigField "String", "LOCALHOST", appConfig.LOCALHOST_RELEASE
            minifyEnabled false
            debuggable true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//            debuggable appConfig.DEBUGABLE
            signingConfig signingConfigs.release
            manifestPlaceholders=[
                    GETUI_APP_KEY      : appConfig.GETUI_APP_KEY
            ]
        }
        debug {
            buildConfigField "String", "LOCALHOST", appConfig.LOCALHOST_DEBUG
            minifyEnabled false
            debuggable true
            signingConfig signingConfigs.debug
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//            debuggable appConfig.DEBUGABLE
            manifestPlaceholders=[
                    GETUI_APP_KEY      : appConfig.GETUI_APP_KEY
            ]
        }
    }
    productFlavors {
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

只用retrofit2进行网络请求

实体类,用于接受返回数据

先来看不用RxJava2的情况

/**
 * @author: yangtianfu
 * @time: 2018/9/3  11:04
 * @more: https://blog.csdn.net/ytfunnysite
 * @Describe
 */
public class Translation {
    private int status;

    private content content;
    private static class content {
        private String from;
        private String to;
        private String vendor;
        private String out;
        private int errNo;
    }

    //定义 输出返回数据 的方法
    public String show() {
        System.out.println(status+"--"+content.from+"--"+content.to+"--"
                +content.vendor+"--"+content.out+"--"+content.errNo);
        return content.out;

    }
}

封装网络请求接口

import com.app.ytf.netdemo.model.Translation;

import io.reactivex.Observable;
import retrofit2.http.GET;

/**
 * @author: yangtianfu
 * @time: 2018/9/3  16:36
 * @more: https://blog.csdn.net/ytfunnysite
 * @Describe 注解里传入 网络请求 的部分URL地址
 *         Retrofit把网络请求的URL分成了两部分:一部分放在Retrofit对象里,另一部分放在网络请求接口里
 *         如果接口里的url是一个完整的网址,那么放在Retrofit对象里的URL可以忽略
 *        采用Observable<...>接口
 *         getCall()是接受网络请求数据的方法
 */
public interface GetRequest {
    @GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20world")
    Observable<Translation> getCall();
}

Retrofit2的实现(使用EventBus更新UI)

  public void request() {

        //步骤4:创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url
                .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
                .build();

        // 步骤5:创建 网络请求接口 的实例
        GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

        //对 发送请求 进行封装
        Call<Translation> call = request.getCall();

        //步骤6:发送网络请求(异步)
        call.enqueue(new Callback<Translation>() {
            //请求成功时候的回调
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                //请求处理,输出结果
                response.body().show();
                EventBus.getDefault().post(response);
            }

            //请求失败时候的回调
            @Override
            public void onFailure(Call<Translation> call, Throwable throwable) {
                System.out.println("连接失败");
            }
        });
    }

此处我们采用了EventBus来更新UI,传递请求结果至主线程,要记得注销

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        EventBus.getDefault().register(this);


    }
    ......

 @Subscribe(threadMode = ThreadMode.MAIN)
    public void setRestult(Response<Translation> response) {
        tvContent.setText(response.body().show());

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

结合RxJava2实现网络请求轮询(无条件)

场景:采用Get方法对 金山词霸API 按规定时间 重复发送网络请求,从而模拟 轮询 需求实现
实体类和接口同上不变,直接看处理方式:

 /**
     * 无条件轮询发送网络请求
     * 参数1 = 第1次延迟时间;
     * 参数2 = 间隔时间数字;
     * 参数3 = 时间单位;
     * 该例子发送的事件特点:延迟2s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
     * 步骤2:每次发送数字前发送1次网络请求(doOnNext()在执行Next事件前调用)
     * 即每隔1秒产生1个数字前,就发送1次网络请求,从而实现轮询需求
     */
    private void getByRxJava() {


//      步骤1:采用interval()延迟发送
        Observable.interval(2, 1, TimeUnit.SECONDS)
//                步骤2:每次发送数字前发送1次网络请求(doOnNext()在执行Next事件前调用)
//                   即每隔1秒产生1个数字前,就发送1次网络请求,从而实现轮询需求
                .doOnNext(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        Log.d(TAG, "第 " + aLong + " 次轮询");
//                        步骤3:通过Retrofit发送网络请求
                        Retrofit retrofit = new Retrofit.Builder()
                                .baseUrl(BuildConfig.LOCALHOST)
                                .addConverterFactory(GsonConverterFactory.create())
                                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                                .build();
//                          创建 网络请求接口 的实例
                        GetRequest getRequest = retrofit.create(GetRequest.class);
                        // c. 采用Observable<...>形式 对 网络请求 进行封装
                        Observable<Translation> observable = getRequest.getCall();
                        // d. 通过线程切换发送网络请求
                        observable.subscribeOn(Schedulers.io()) // 切换到IO线程进行网络请求
                                .observeOn(AndroidSchedulers.mainThread()) // 切换回到主线程 处理请求结果
                                .subscribe(new Observer<Translation>() {
                                    @Override
                                    public void onSubscribe(Disposable d) {

                                    }

                                    @Override
                                    public void onNext(Translation translation) {
                                        String result = translation.show();
                                        tvContent.setText(result);

                                    }

                                    @Override
                                    public void onError(Throwable e) {


                                    }

                                    @Override
                                    public void onComplete() {

                                    }
                                });


                    }
                }).subscribe(new Observer<Long>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.e(TAG, "执行doOnNext->onSubscribe方法!");
            }

            @Override
            public void onNext(Long aLong) {
                Log.e(TAG, "网络初始化完成!");

            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "网络初始化失败!" + e.toString());
            }

            @Override
            public void onComplete() {
                Log.e(TAG, "执行doOnNext->onComplete方法!");
            }
        });
    }

结合RxJava2实现网络请求轮询(有条件)

基本操作依然同上,加入轮询条件变量 int i=0;

/**
     * @author: yangtianfu
     * @time: 2018/9/4  16:26
     * @more: https://blog.csdn.net/ytfunnysite
     * @Describe 有条件的网络轮询,定义i为4的时候停止轮询
     */
    private void getByRxJavaWithConditional() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BuildConfig.LOCALHOST)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        GetRequest getRequest = retrofit.create(GetRequest.class);
        Observable<Translation> call = getRequest.getCall();
        call.repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
            // 在Function函数中,必须对输入的 Observable<Object>进行处理,此处使用flatMap操作符接收上游的数据
            @Override
            public ObservableSource<?> apply(Observable<Object> objectObservable){
                // 将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据传递给1个新被观察者(Observable)
                // 以此决定是否重新订阅 & 发送原来的 Observable,即轮询 // 此处有2种情况:
                // 1. 若返回1个Complete() / Error()事件,则不重新订阅 & 发送原来的 Observable,即轮询结束
                // 2. 若返回其余事件,则重新订阅 & 发送原来的 Observable,即继续轮询


                return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(Object o) {
                        // 加入判断条件:当轮询次数 = 5次后,就停止轮询
                        if (i > 3) {
                    // 此处选择发送onError事件以结束轮询,因为可触发下游观察者的onError()方法回调
                            Observable.error(new Throwable("轮询结束"));
                        }
                        // 若轮询次数<4次,则发送1Next事件以继续轮询
                        // 注:此处加入了delay操作符,作用 = 延迟一段时间发送(此处设置 = 2s)
                        return Observable.just(1).delay(2000,TimeUnit.SECONDS);
                    }
                });
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Translation>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Translation translation) {
                        // e.接收服务器返回的数据
                        String result = translation.show();
                        tvContent.setText(result);
                        i++;
                        Log.e(TAG, "onNext: 第"+i+"次轮询" );


                    }

                    @Override
                    public void onError(Throwable e) {
                        // 获取轮询结束信息
                        Log.d(TAG, e.toString());

                    }

                    @Override
                    public void onComplete() {

                    }
                });

    }

结合RxJava2网络请求嵌套回调(FlatMap)

场景:在第1个网络请求成功后,继续再进行一次网络请求
如 先进行 用户注册 的网络请求, 待注册成功后回再继续发送 用户登录 的网络请求
结合 RxJava2中的变换操作符FlatMap()实现嵌套网络请求,采用Get方法对 金山词霸API 发送网络请求
即先翻译 Register(注册),再翻译 Login(登录)

两个网络请求对应的实体类

public class Translation {
    private int status;

    private content content;
    private static class content {
        private String from;
        private String to;
        private String vendor;
        private String out;
        private int errNo;
    }

    //定义 输出返回数据 的方法
    public String show() {
        System.out.println(status+"--"+content.from+"--"+content.to+"--"
                +content.vendor+"--"+content.out+"--"+content.errNo);
        return content.out;

    }
}
public class Translation2 {
    private int status;

    private content content;
    private static class content {
        private String from;
        private String to;
        private String vendor;
        private String out;
        private int errNo;
    }

    //定义 输出返回数据 的方法
    public String show() {
        System.out.println(status+"--"+content.from+"--"+content.to+"--"
                +content.vendor+"--"+content.out+"--"+content.errNo);
        return content.out;

    }
}

接口封装(注册接口和登录接口)

/**
 * @author: yangtianfu
 * @time: 2018/9/4  17:19
 * @more: https://blog.csdn.net/ytfunnysite
 * @Describe注解里传入 网络请求 的部分URL地址
 * Retrofit把网络请求的URL分成了两部分:一部分放在Retrofit对象里,另一部分放在网络请求接口里
 * 如果接口里的url是一个完整的网址,那么放在Retrofit对象里的URL可以忽略
 * 采用Observable<...>接口 // getCall()是接受网络请求数据的方法
 */
public interface GetRequest_Interface {
    // 网络请求1
    @GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20register")
    Observable<Translation> getCall();
    // 网络请求2
    @GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20login")
    Observable<Translation2> getCall_2();
}

使用flatMap进行嵌套请求

/**
* @author: yangtianfu
* @time: 2018/9/4  17:17
* @more: https://blog.csdn.net/ytfunnysite
* @Describe 通过 公共的金山词霸API 来模拟 “注册 - 登录”嵌套网络请求
 * 即先翻译 Register(注册),再翻译 Login(登录)
*/
    private void getByRxJavaInFlatMap() {
        // 步骤1:创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BuildConfig.LOCALHOST)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 步骤2:创建 网络请求接口 的实例
        GetRequest_Interface getRequest_interface=retrofit.create(GetRequest_Interface.class);
        // 步骤3:采用Observable<...>形式 对 2个网络请求 进行封装
        observable1= getRequest_interface.getCall();
        observable2=getRequest_interface.getCall_2();
        observable1.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnNext(new Consumer<Translation>() {
                        @Override
                        public void accept(Translation translation) throws Exception {
                            Log.d(TAG, "第1次网络请求成功");
                            String result=translation.show();
                            tvContent.setText(result); // 对第1次网络请求返回的结果进行操作 = 显示翻译结果
                        }
                    })
                //再次切回Io线程进行第二次网络请求
                .observeOn(Schedulers.io())
                 // (新被观察者,同时也是新观察者)切换到IO线程去发起登录请求
                // 特别注意:因为flatMap是对初始被观察者作变换,所以对于旧被观察者,它是新观察者,所以通过observeOn切换线程
                .flatMap(new Function<Translation, ObservableSource<Translation2>>() {
                    @Override
                    public ObservableSource<Translation2> apply(Translation result) throws Exception {
                        // 将网络请求1转换成网络请求2,即发送网络请求2
                        return observable2;
                    }
                })
                // (初始观察者)切换到主线程 处理网络请求2的结果
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Translation2>() {
                    @Override
                    public void accept(Translation2 translation2) throws Exception {
                        Log.d(TAG, "第2次网络请求成功");
                        String result2 = translation2.show();
                        String text = tvContent.getText().toString();
                        tvContent.setText(text + "-" + result2);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        System.out.println("登录失败");
                    }
                });

    }

猜你喜欢

转载自blog.csdn.net/ytfunnysite/article/details/82387975