Android RxJava应用:优雅实现网络请求嵌套回调

前言

  • Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。

Github截图

今天,我将为大家带来 Rxjava创建操作符的实际开发需求场景:网络请求嵌套回调 需求 ,并结合RetrofitRxJava 实现,希望大家会喜欢。

Carson带你学RxJava系列文章,包括 原理、操作符、应用场景、背压等等,请看文章:Android:这是一份全面 & 详细的RxJava学习指南


目录

示意图


1. 需求场景

1.1 背景

需要进行嵌套网络请求:即在第1个网络请求成功后,继续再进行一次网络请求

如 先进行 用户注册 的网络请求, 待注册成功后回再继续发送 用户登录 的网络请求

1.2 冲突

嵌套实现网络请求较为复杂,即嵌套调用函数

下面展示的是结合 RetrofitRxJava的基本用法,即未用操作符前

// 发送注册网络请求的函数方法
    private void register() {
        api.register(new RegisterRequest())
                .subscribeOn(Schedulers.io())               //在IO线程进行网络请求
                .observeOn(AndroidSchedulers.mainThread())  //回到主线程去处理请求结果
                .subscribe(new Consumer<RegisterResponse>() {
                    @Override
                    public void accept(RegisterResponse registerResponse) throws Exception {
                        Toast.makeText(MainActivity.this, "注册成功", Toast.LENGTH_SHORT).show();
                        login();   //注册成功, 调用登录的方法
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Toast.makeText(MainActivity.this, "注册失败", Toast.LENGTH_SHORT).show();
                    }
                });
    }


// 发送登录网络请求的函数方法
private void login() {
        api.login(new LoginRequest())
                .subscribeOn(Schedulers.io())               //在IO线程进行网络请求
                .observeOn(AndroidSchedulers.mainThread())  //回到主线程去处理请求结果
                .subscribe(new Consumer<LoginResponse>() {
                    @Override
                    public void accept(LoginResponse loginResponse) throws Exception {
                        Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                    }
                });
    }

1.3 解决方案

结合 RxJava2中的变换操作符FlatMap()实现嵌套网络请求

关于该操作符的使用具体请看文章:Android RxJava:图文详解 变换操作符


2. 功能说明

  • 实现功能:发送嵌套网络请求(将英文翻译成中文,翻译两次)
  1. 为了让大家都能完成Demo,所以通过 公共的金山词霸API 来模拟 “注册 - 登录”嵌套网络请求
  2. 即先翻译 Register(注册),再翻译 Login(登录)
  • 实现方案:采用Get方法对 金山词霸API 发送网络请求

采用 Gson 进行数据解析

金山词典


3. 具体实现

下面我将结合 RetrofitRxJava 实现网络请求嵌套

3.1 步骤说明

  1. 添加依赖
  2. 创建 接收服务器返回数据 的类
  3. 创建 用于描述网络请求 的接口(区别于Retrofit传统形式)
  4. 创建 Retrofit 实例
  5. 创建 网络请求接口实例 并 配置网络请求参数(区别于Retrofit传统形式)
  6. 发送网络请求(区别于Retrofit传统形式)
  7. 发送网络请求
  8. 对返回的数据进行处理

本实例侧重于说明 RxJava 的线程控制,关于Retrofit的使用请看文章:这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)

3.2 步骤实现

步骤1: 添加依赖

a. 在 Gradle加入Retrofit库的依赖

build.gradle

dependencies {

// Android 支持 Rxjava
// 此处一定要注意使用RxJava2的版本
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

// Android 支持 Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'

// 衔接 Retrofit & RxJava
// 此处一定要注意使用RxJava2的版本
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

// 支持Gson解析
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

}

b. 添加 网络权限
AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
步骤2:创建 接收服务器返回数据 的类
  • 金山词霸API 的数据格式说明如下:
// URL模板
http://fy.iciba.com/ajax.php

// URL实例
http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world

// 参数说明:
// a:固定值 fy
// f:原文内容类型,日语取 ja,中文取 zh,英语取 en,韩语取 ko,德语取 de,西班牙语取 es,法语取 fr,自动则取 auto
// t:译文内容类型,日语取 ja,中文取 zh,英语取 en,韩语取 ko,德语取 de,西班牙语取 es,法语取 fr,自动则取 auto
// w:查询内容
  • 示例

API格式说明

  • 根据 金山词霸API 的数据格式,创建 接收服务器返回数据 的类:

为了演示是2个网络请求,所以对应设置2个接收服务器的数据类

<-- Translation1.java -->
public class Translation1 {
    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 void show() {

        Log.d("RxJava", "翻译内容 = " + content.out);

    }
}

<-- Translation2.java -->
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 void show() {

        Log.d("RxJava", "翻译内容 = " + content.out);

    }
}
步骤3:创建 用于描述网络请求 的接口

采用 注解 + Observable<...>接口描述 网络请求参数

GetRequest_Interface.java

public interface GetRequest_Interface {

    // 网络请求1
    @GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20register")
    Observable<Translation1> getCall();

    // 网络请求2
    @GET("ajax.php?a=fy&f=auto&t=auto&w=hi%20login")
    Observable<Translation2> getCall_2();

    // 注解里传入 网络请求 的部分URL地址
    // Retrofit把网络请求的URL分成了两部分:一部分放在Retrofit对象里,另一部分放在网络请求接口里
    // 如果接口里的url是一个完整的网址,那么放在Retrofit对象里的URL可以忽略
    // 采用Observable<...>接口
    // getCall()是接受网络请求数据的方法

}
接下来的步骤均在MainActivity.java内实现(请看注释)

MainActivity.java

public class MainActivity extends AppCompatActivity {

        private static final String TAG = "Rxjava";

        // 定义Observable接口类型的网络请求对象
        Observable<Translation1> observable1;
        Observable<Translation2> observable2;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

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

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

            // 步骤3:采用Observable<...>形式 对 2个网络请求 进行封装
            observable1 = request.getCall();
            observable2 = request.getCall_2();


            observable1.subscribeOn(Schedulers.io())               // (初始被观察者)切换到IO线程进行网络请求1
                       .observeOn(AndroidSchedulers.mainThread())  // (新观察者)切换到主线程 处理网络请求1的结果
                       .doOnNext(new Consumer<Translation1>() {
                        @Override
                        public void accept(Translation1 result) throws Exception {
                            Log.d(TAG, "第1次网络请求成功");
                            result.show();
                            // 对第1次网络请求返回的结果进行操作 = 显示翻译结果
                        }
                    })

                    .observeOn(Schedulers.io())                 // (新被观察者,同时也是新观察者)切换到IO线程去发起登录请求
                                                                // 特别注意:因为flatMap是对初始被观察者作变换,所以对于旧被观察者,它是新观察者,所以通过observeOn切换线程
                                                                // 但对于初始观察者,它则是新的被观察者
                    .flatMap(new Function<Translation1, ObservableSource<Translation2>>() { // 作变换,即作嵌套网络请求
                        @Override
                        public ObservableSource<Translation2> apply(Translation1 result) throws Exception {
                            // 将网络请求1转换成网络请求2,即发送网络请求2
                            return observable2;
                        }
                    })

                    .observeOn(AndroidSchedulers.mainThread())  // (初始观察者)切换到主线程 处理网络请求2的结果
                    .subscribe(new Consumer<Translation2>() {
                        @Override
                        public void accept(Translation2 result) throws Exception {
                            Log.d(TAG, "第2次网络请求成功");
                            result.show();
                            // 对第2次网络请求返回的结果进行操作 = 显示翻译结果
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            System.out.println("登录失败");
                        }
                    });
    }
}
3.3 测试结果

示意图


4. Demo地址

Carson_Ho的Github地址 = RxJava2实战系列:网络请求嵌套回调

喜欢的麻烦点个star


5. 总结

  • 本文主要讲解了 Rxjava 变换操作符的实际开发需求场景:嵌套回调需求 ,并结合RetrofitRxJava 实现
  • Carson带你学RxJava系列文章:

入门
Carson带你学Android:这是一篇清晰易懂的Rxjava入门教程
Carson带你学Android:这是一份面向初学者的RxJava使用指南
Carson带你学Android:RxJava2.0到底更新了什么?(含使用建议)
原理
Carson带你学Android:图文解析RxJava原理
Carson带你学Android:手把手带你源码分析RxJava
使用教程(操作符)
Carson带你学Android:RxJava操作符教程
Carson带你学Android:RxJava创建操作符
Carson带你学Android:RxJava功能性操作符
Carson带你学Android:RxJava过滤操作符
Carson带你学Android:RxJava组合/合并操作符
Carson带你学Android:RxJava变换操作符
Carson带你学Android:RxJava条件/布尔操作符
应用
Carson带你学Android:什么时候应该使用Rxjava?(开发场景汇总)
Carson带你学Android:RxJava线程控制(含实例讲解)
Carson带你学Android:图文详解RxJava背压策略
Carson带你学Android:RxJava、Retrofit联合使用汇总(含实例教程)
Carson带你学Android:优雅实现网络请求嵌套回调
Carson带你学Android:网络请求轮询(有条件)
Carson带你学Android:网络请求轮询(无条件)
Carson带你学Android:网络请求出错重连(结合Retrofit)
Carson带你学Android:合并数据源
Carson带你学Android:联想搜索优化
Carson带你学Android:功能防抖
Carson带你学Android:从磁盘/内存缓存中获取缓存数据
Carson带你学Android:联合判断


欢迎关注Carson_Ho的CSDN博客 与 公众号!

博客链接:https://carsonho.blog.csdn.net/


请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

  • 21
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
好的,我会为你提供关于MyBatis使用association标签实现嵌套查询的详细解释。 在MyBatis中,association标签常用于处理一对一关系的数据,它允许我们在查询结果中嵌套查询其它表的数据。下面是一个使用association标签实现嵌套查询的示例: ``` <resultMap id="userResultMap" type="User"> <id property="id" column="user_id" /> <result property="username" column="username" /> <result property="email" column="email" /> <association property="profile" javaType="Profile"> <id property="id" column="profile_id" /> <result property="firstName" column="first_name" /> <result property="lastName" column="last_name" /> </association> </resultMap> ``` 在上面的示例中,我们定义了一个resultMap来映射查询结果到User对象。在这个resultMap中,我们使用了association标签来处理User和Profile表之间的一对一关系。具体来说,我们在User对象中定义了一个名为profile的属性,它的类型是Profile。然后我们使用association标签来定义Profile对象的映射规则,包括它的id和firstName、lastName等属性。这样,在查询User表时,MyBatis会自动关联查询Profile表,并将查询结果映射到User对象的profile属性中。 需要注意的是,在使用association标签时,我们需要确保查询语句中包含了所有需要的字段,包括User表和Profile表的字段。否则,MyBatis将无法正确地进行嵌套查询。 希望这个解释对你有所帮助,如果你还有其它问题,可以继续向我提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值