美文网首页
Rxjava2-小白入门(三)

Rxjava2-小白入门(三)

作者: g小志 | 来源:发表于2017-10-09 16:41 被阅读0次

    前言

    继续上篇的Rxjava2的入门实例,把剩下的运用Rxjava的实例讲下,首先要说名下本文会用到Rxbinding的知识,他相当于Rxjava的辅助工具,在引入他的时候会自动帮我们引入Rxjava,在本文中我就不具体讲解了,用法比较简单,没解除的同学找些相关的文章,相信很快就能上手的,。在这里我把依赖写下

    compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
    

    这个版本默认引入的是Rxjava2.0.2的版本


    Rxjava2的操作符

    • create
    • just
    • fromArray
    • map
    • flatMap
    • zip
    • filter
    • time
    • merge
    • retry
    • retryWhen
    • range
    • Interval
    • ...

    Rxjava2的使用场景

    • 登陆后获取用户信息
    • 关键词搜索
    • 防止按钮重复点击
    • 购物车合并本地和网络数据
    • 发送验证码倒计时

    关键词搜索

    一般情况我们监听EditText控件,当值发生改变去请求搜索接口,如下:


    a: 可能导致很多没有意义的请求,耗费用户流量(因为控件的值每更改一次立即就会去请求网络,而且只是最后输入的关键字是有用的)

    b:可能导致最终搜索的结果不是用户想要的.
    例如,用户一开始输入关键字’AB’ 这个时候出现两个请求, 一个请求是A关键字, 一个请求是AB关键字. 表面上是’A’请求先发出去, ‘AB’请求后发出去. 如果后发出去的’AB’请求先返回, ‘A’请求后返回,那么’A’请求后的结果将会覆盖’AB’请求的结果. 从而导致搜索结果不正确.

    在写代码之前我们先介绍下我们要用到的操作符debounce它属于过滤操作符



    这是官方文档给出的解释,从解释中我们也不难看出他的用法。那么下面我在实例中去使用吧!

     RxTextView.textChanges(mView)//通过Rxbinding的textChanges()监听AutoCompleteTextView文字的变化,他是一个Obervable对象
                    .debounce(200, TimeUnit.MILLISECONDS)//利用debounce操作符延迟发送 TimeUnit.MILLISECONDS(毫秒)指定一个参数的单位
                    .subscribeOn(AndroidSchedulers.mainThread())//通过Rxbinding监听控件必须在主线程
                    .filter(new Predicate<CharSequence>() {
                        @Override
                        public boolean test(CharSequence charSequence) throws Exception {
                            //过滤为空的数据 避免多余请求
                            return charSequence.toString().trim().length() > 0;
                        }
                    })
                    .flatMap(new Function<CharSequence, ObservableSource<List<String>>>() {
                        @Override
                        public ObservableSource<List<String>> apply(CharSequence charSequence) throws Exception {
                            Log.d(TAG, "apply: " + charSequence.toString());
                            String request = charSequence.toString().trim();//输入的内容
                            /**
                             * 通过输入的内容request发起网络请求
                             * 返回一个模糊匹配的字符串集合用于显示
                             * 这里我们构建一个假的数据
                             */
                            List<String> mList = new ArrayList<String>();
                            mList.add("abc");
                            mList.add("abd");
                            mList.add("abop");
                            mList.add("ac");
                            return Observable.just(mList);
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<List<String>>() {
                        @Override
                        public void accept(List<String> strings) throws Exception {
                            Log.d(TAG, "accept: " + strings.toString());
                            ArrayAdapter<String> adapter = new ArrayAdapter<String>
                                    (getApplicationContext(), android.R.layout.simple_list_item_1, android.R.id.text1, strings);
                            mView.setAdapter(adapter);
                        }
                    });
        }
    

    这就是一个简单模拟关键词搜索的实例,但是虽然我们满足了上面提到的要求a,但是要求b也就是可能返回的数据先后不同可能会导致结果不是们想要的,那么该怎么处理呢?通过文档我们找到了这样一个操作符switchMap,让我们来看看他的使用



    这个操作符正好符合我们的业务要求,同时他也属于变换操作符,所以我们自需要把flatmap改成switchMap就可以了。这样我们2者的区别和debounce的用法结合实例是不是更加深刻呢?


    防止按钮重复(连续)点击

    在实际应用中可能在提交信息,登录的时候每次点击按钮就会发送网络请求,当网络比较慢的时候或是其他原因已经请求网路只是返回的数据比较慢,当我们连续点击就会连续的发送请求,这样的结果必然不是我们想要的。

    ThrottleFirst:
    允许设置一个时间长度,之后它会发送固定时间长度内的第一个事件,而屏蔽其它事件,在间隔达到设置的时间后,可以再发送下一个事件

    这个操作符就很好的解决了这个问题

     RxView.clicks(mButton).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Consumer<Object>() {
                @Override
                public void accept(Object o) throws Exception {
                    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String dateStr = dateformat.format(System.currentTimeMillis());
                    Log.d(TAG, "accept: "+dateStr);
                }
            });
    

    我在不断点击的情况下,输出结果:

    10-08 21:51:07.008 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:07
    10-08 21:51:09.168 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:09
    10-08 21:51:11.308 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:11
    10-08 21:51:13.398 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:13
    

    可以看到2秒内自能点击一次。

    注意:此时可以用ThrottleFirst也可以用debounce 效果是一样的 但是 ThrottleFirst发出的是第一个 debounce 发出的是最后一个 都是保证单位时间内只能发送一次 但是原理还是有些不同的,过会2个例子也不难比较区别


    购物车合并本地和网络数据

    现在有这么一种情况,你在上班的时候偷偷用电脑上淘宝准备买衣服看重了一双鞋子和衣服加入购物车。在回家的路上用手机又加入购物车裤子和衬衫。等你回家的时候准备用手机购买,购物车里应该是所有的商品都在的,那么我们就需要把手机的和web端合并在一起并展示。这时我们就可以用到merge操作符。

    在使用前我们先了解下merge:



    关于merge的官方文档和图片分析还是比较简单的。不理解的话等我们讲完实例后回头在来看看。下面是具体代码:

      mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(final View v) {
    
                    /*两者合并*/
                    Observable.merge(getObervableLocal(), getObervableWeb()).subscribeOn(Schedulers.io()).
                            observeOn(AndroidSchedulers.mainThread()).
                            subscribe(new Consumer<List<User>>() {
                                @Override
                                public void accept(List<User> users) throws Exception {
                                    for (int i = 0; i <users.size() ; i++) {
                                        Log.d(TAG, "accept: "+users.get(i).getName());
                                    }
                                }
                            });
                }
            });
        }
        /**
         * 本地数据(从数据库中取)
         *
         * @return 返回本地数据(手机端)的购物车信息
         */
        public Observable<List<User>> getObervableLocal() {
            //用User对象代表商品实例
            //我们用手机购买一般数据会缓存到手机的数据库当中
            User user = new User("裤子", "16元");
            User user1 = new User("衬衫", "18元");
    
            List<User> mList = new ArrayList<>();
            mList.add(user);
            mList.add(user1);
            return Observable.just(mList);
        }
    
        /**
         * web数据(从网络中请求)
         *
         * @return 返回网络数据
         */
        public Observable<List<User>> getObervableWeb() {
            //网络请求 查看服务器购物车是否有数据
            User user = new User("衣服", "20元");
            User user1 = new User("裤子", "22元");
    
            List<User> mList = new ArrayList<>();//模拟请求返回的数据
            mList.add(user);
            mList.add(user1);
            return Observable.fromArray(mList).subscribeOn(Schedulers.io());//网络请求在子线程
        }
    
    
    

    运行结果:

    10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 裤子
    10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 衬衫
    10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 衣服
    10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 裤子
    

    注意其实合并的操作符还有zip和zipWith,其实2者差不多只是参数不一样。用法也是比较简单zip操作符也可以看看这篇文章。实际操作下会更加深印象。这里我就不咱代码了。


    发送验证码倒计时

    这个实例我们用到Interval操作符:



    具体代码操作:



    所有的实例都讲完了我们在看下retryWhen和retry,range操作符。

    retry操作符

    retryWhen和retry的主要区别概括来说就是retryWhen将错误的信息发送下去(出错了就发送错误信息),retry是出错了会先尝试重新订阅再发送一变,当达到设置的重试次数时还没有成功才会发出错误的信息


    总结:感觉文章写的好乱,主要的原因是因为本身也在学习中很多东西总结的不够透彻,虽然看了很多文章但是自己写起来还是会乱乱的,以后会努力希望一次比一次好,作为小白,这是我自身的学习笔记。如果有错误希望大家指出,我将不胜感激。

    推荐文章:
    Rxjava2
    RxJava2操作符
    RxJava/RxAndroid 使用实例实践
    Rxjava2我觉得关于rxjava2这个系列真的非常好很值得学习

    代码地址

    相关文章

      网友评论

          本文标题:Rxjava2-小白入门(三)

          本文链接:https://www.haomeiwen.com/subject/vtepyxtx.html