RxJava(十四)interval、takeWhile 操作符实现获取验证码功能

15 篇文章 42 订阅

RxJava 系列文章目录导读:

一、RxJava create 操作符的用法和源码分析
二、RxJava map 操作符用法详解
三、RxJava flatMap 操作符用法详解
四、RxJava concatMap 操作符用法详解
五、RxJava onErrorResumeNext 操作符实现 app 与服务器间 token 机制
六、RxJava retryWhen 操作符实现错误重试机制
七、RxJava 使用 debounce 操作符优化 app 搜索功能
八、RxJava concat 操作处理多数据源
九、RxJava zip 操作符在 Android 中的实际使用场景
十、RxJava switchIfEmpty 操作符实现 Android 检查本地缓存逻辑判断
十一、RxJava defer 操作符实现代码支持链式调用
十二、combineLatest 操作符的高级使用
十三、RxJava 导致 Fragment Activity 内存泄漏问题
十四、interval、takeWhile 操作符实现获取验证码功能
十五、RxJava 线程的自由切换


现在主流的 App 中,使用手机验证码的场景越来越多,比如验证码登陆、验证码重置/找回密码等。

一般功能流程如下:

  1. 防止获取验证码按钮在短时间内被点击多次

  2. 调用获取验证码接口(提示 loading,防止界面被操作)

  3. 验证码获取成功开始倒计时,此时按钮不可被点击

  4. 倒计时完毕后,点击可以再次被点击

在 Android 中实现该功能的方案也有很多,比如 Timer、CountDownTimer、Handler 等。

接下来主要是讲如何使用 RxJava 来实现该功能。

点击按钮调用获取验证码接口可能有两种交互

  • 调用获取验证码接口,如果是弹出一个 loading 框,这样的最简单,因为用户不能再次点这个按钮了
    (接口返回成功则开始倒计时,失败则 loading 消失按钮可以再次被点击)

  • 调用获取验证码接口,不实用 loading 框的方式,直接让按钮不可点,按钮的文字变成 正在获取... 之类的。
    接口调用成功则开始倒计时,接口失败则把按钮设置为可点

这两种方式用 RxJava 都可以轻松实现。第一种方式主流一些,以下讲第一种交互实现方式。

代码如下:

RxView.clicks(mBtn)
		.throttleFirst(1, TimeUnit.SECONDS)
		.flatMap(new Func1<Void, Observable<Boolean>>() {
			@Override
			public Observable<Boolean> call(Void aVoid) {
				//弹出loading框(省略)
				//调用获取验证码接口 (省略)
				return Observable.just(true);
			}
		})
		.flatMap(new Func1<Boolean, Observable<Boolean>>() {
			@Override
			public Observable<Boolean> call(Boolean aBoolean) {
				//验证码获取成功,把按钮置为不可点
				mBtn.setEnabled(false);
				//关闭loading框(省略)
				return intervalButton();
			}
		})
		.observeOn(AndroidSchedulers.mainThread())
		.subscribe(new Action1<Boolean>() {
			@Override
			public void call(Boolean aBoolean) {
				Log.e("FetchPhoneCodeFragment", "subscribe call");
			}
		}, new Action1<Throwable>() {
			@Override
			public void call(Throwable throwable) {
				throwable.printStackTrace();
				//关闭loading框(省略)
				//出错后把按钮设置为可用
				mBtn.setEnabled(true);
				Toast.makeText(getActivity(), throwable.getMessage(), Toast.LENGTH_SHORT).show();
			}
		});

获取验证码成功后,开始倒计时

   public Observable<Boolean> intervalButton() {
        //如果使用Observable.interval(interval, TimeUnit),会默认延迟interval执行
        return Observable.interval(0, 1000, TimeUnit.MILLISECONDS) // ,每秒发射一次事件
				//如果aLong小于等于我们设定的秒数,发射事件
                .takeWhile(new Func1<Long, Boolean>() {
                    @Override
                    public Boolean call(Long aLong) {
                        return aLong <= INTERVAL_TIME;
                    }
                })

				//可以通过filter达到takeWhile相同的效果
//                .filter(new Func1<Long, Boolean>() {
//                    @Override
//                    public Boolean call(Long aLong) {
//                        return aLong <= INTERVAL_TIME;
//                    }
//                })
                .observeOn(AndroidSchedulers.mainThread())
                .flatMap(new Func1<Long, Observable<Boolean>>() {
                    @Override
                    public Observable<Boolean> call(Long aLong) {
                        long diff = INTERVAL_TIME - aLong;
                        Log.e("FetchPhoneCodeFragment", "thread name:" + Thread.currentThread().getName() + ",aLong:" + aLong + ",diff:" + diff);
                        mBtn.setText(diff + "s");
                        //倒计时完毕后,按钮可以再次被点击,重新设置按钮文案
                        if (diff == 0) {
                            mBtn.setEnabled(true);
                            mBtn.setText("获取验证码");
                        }
                        return Observable.just(true);
                    }
                });
    }


上面的注释也很详细,这里就简单的概述下:

  • 通过 RxView 的 throttleFirst 避免在短时间内按钮被点击多次

  • 调用获取验证码接口把按钮置为不可用,并且弹出 loading 框,如果接口调用成功了则开始倒计时,如果失败的话关闭 loading 框,把按钮设置为可用。

  • 倒计时功能,到了我们预设的秒数,把按钮置为可用, 否则按钮不可用。

需要注意的是 interval 定时发射数据都会执行 subscribe action;而且不取消的话,interval 会一直发射数据,所以使用 takeWhile、filter 来作为条件判断。

另一方面,在 onDestroy 的时候需要把 Subscription 反注销:

@Override
public void onDestroy() {
	super.onDestroy();
	if (mSubscription != null && !mSubscription.isUnsubscribed()) {
		mSubscription.unsubscribe();
	}
}


如果你觉得本文帮助到你,给我个关注和赞呗!

另外,我为 Android 程序员编写了一份:超详细的 Android 程序员所需要的技术栈思维导图

如果有需要可以移步我的 GitHub -> AndroidAll,里面包含了最全的目录和对应知识点链接,帮你扫除 Android 知识点盲区。 由于篇幅原因只展示了 Android 思维导图:
超详细的Android技术栈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiclaim

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值