欢迎转载,转载请标明出处:

http://blog.csdn.net/johnny901114/article/details/51555203

本文出自:【余志强的博客】

一、抛出问题

现在几乎所有的App都有搜索功能 , 一般情况我们监听EditText控件,当值发生改变去请求搜索接口. 如:

etKey.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    }

    @Override
    public void afterTextChanged(Editable s) {
        String key = etKey.getText().toString().trim();
        if (key.length() > 0){
            search(key);// 请求搜索接口,成功后把结果显示到界面上.
        }
    }
});

这样做有两个问题:

  • 可能导致很多没有意义的请求,耗费用户流量(因为控件的值每更改一次立即就会去请求网络,而且只是最后输入的关键字是有用的)
  • 可能导致最终搜索的结果不是用户想要的. 例如,用户一开始输入关键字’AB’ 这个时候出现两个请求, 一个请求是A关键字, 一个请求是AB关键字. 表面上是’A’请求先发出去, ‘AB’请求后发出去. 如果后发出去的’AB’请求先返回, ‘A’请求后返回,那么’A’请求后的结果将会覆盖’AB’请求的结果. 从而导致搜索结果不正确.

二、如何解决问题

使用强大的RxJava的 debounce操作符 可以解决这个问题。

subscription = RxTextView.textChanges(etKey)
                .debounce(400, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())// 对etKey[EditText]的监听操作 需要在主线程操作
                //对用户输入的关键字进行过滤
                .filter(new Func1<CharSequence, Boolean>() {
                    @Override
                    public Boolean call(CharSequence charSequence) {
                        Log.d("RxJava", "filter is main thread : " + (Looper.getMainLooper() == Looper.myLooper()));
                        return charSequence.toString().trim().length() > 0;
                    }
                })
                .flatMap(new Func1<CharSequence, Observable<List<String>>>() {
                    @Override
                    public Observable<List<String>> call(CharSequence charSequence) {
                        Log.d("RxJava", getMainText("flatMap"));
                        return searchApi.search(charSequence.toString());
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<String>>() {
                    @Override
                    public void call(List<String> strings) {
                        tvContent.setText("search result:\n\n");
                        tvContent.append(strings.toString());
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        throwable.printStackTrace();
                        tvContent.append("Error:" + throwable.getMessage());
                    }
                });

上面代码的主要逻辑:

  • 使用debounce操作符设置: 只有当用户输入关键字后400毫秒才发射数据[说的直白点就是400毫秒后才会走后面的逻辑];
  • 使用filter操作符 对用户输入的关键字进行过滤:只有输入的关键字不为空,才会走后面的逻辑;
  • 使用flatMap操作符:使用最终的关键字去请求搜索接口

至此,避免EditText每改变一次就请求一次的情况。

但是,还有一个问题,上面说的导致搜索结果的错乱,上面的代码还是没有解决,比如停止输入400毫秒后, 那么肯定会开始请求Search接口, 但是用户又会输入新的关键字,这个时候上个请求还没有返回, 新的请求又去请求Search接口.这个时候有可能最后的一个请求返回, 第一个请求最后返回,导致最终显示的结果是第一次搜索的结果.

怎么去解决这个问题:可以使用switchMap操作符解决。

看看官网对 switchMap操作符 如何解释的:

Returns a new Observable by applying a function that you supply to each item emitted by the source Observable that returns an Observable,
and then emitting the items emitted by the most recently emitted of these Observables.

switchMap操作符flatMap操作符 差不多,区别是switchMap操作符只会发射[emit]最近的Observables。

也就是说,当400毫秒后,发出第一个搜索请求,当这个请求的过程中,用户又去搜索了,发出第二个请求,不管怎样,switchMap操作符只会发射第二次请求的Observable。所以,在上面的代码基础上把flatMap改成switchMap就可以了。


github源码下载

RxJava(七) 使用debounce操作符 优化app搜索功能的更多相关文章

  1. Vue2.5开发去哪儿网App 搜索功能完成

    效果展示: Search.vue: <div class="search-content" ref="search" v-show="keywo ...

  2. 开发手机APP过程,不同使用场景APP搜索框的样式及区别

    搜索框是 app 内最常见的控件之一,可以帮助用户快速又精准找到期望的内容与功能.不同的使用场景下,根据页面中搜索的重要程度,搜索框也有着不同的样式. 下面就常州开发APP公司和大家聊聊常见的四种样式 ...

  3. RxJava系列4(过滤操作符)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  4. RxJava【过滤】操作符 filter distinct throttle take skip first MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  5. 云搜索服务在APP搜索场景的应用

    搜索无处不在,尤其是在移动互联的今天.无论是社交,电商,还是视频等APP中,搜索都已经在其中扮演了重要的角色.作为信息的入口,搜索能帮用户从海量信息中找到想要的信息.在APP搜索的典型场景如下: ●  ...

  6. RxJava2实战---第七章 合并操作符和连接操作符

    RxJava2实战---第七章 合并操作符和连接操作符 RxJava的合并操作符: startWith():在数据序列的开头增加一项数据. merge:将多个Observable合并为一个. merg ...

  7. 5个可以帮你优化App的优秀网站

    也许现在有一款App可以提供所有你需要的,你不需要的,或者你可以想象到的内容.但是,有多少App真的可以不仅满足需求而且还能提供很好的用户体验呢? 相信很多APP并没有这样的能力.有一些APP的设计特 ...

  8. 011.Adding Search to an ASP.NET Core MVC app --【给程序添加搜索功能】

    Adding Search to an ASP.NET Core MVC app 给程序添加搜索功能 2017-3-7 7 分钟阅读时长 作者 本文内容 1.Adding Search by genr ...

  9. Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP

    Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP 项目截图     这是我的目录结构 五步使用RxJava+Retrofit2+Okhttp+RxCache 第一步 ...

随机推荐

  1. 机器学习基石:05 Training versus Testing

    train:A根据给定训练集D在H中选出g,使得Ein(g)约等于0: test:g在整个输入空间X上的表现要约等于在训练集D上的表现,使得Eout(g)约等于Ein(g). 如果|H|小,更易保证t ...

  2. 使用Keras对交通标志进行分类

    # 使用Keras对交通标志进行分类 一.概述 本文主要记录的在使用Keras过程中,实现交通标志分类,数据集使用的是. 文本主要使用的环境为: Python3.5.2 Tensorflow 1.7 ...

  3. luogu2252 取石子游戏

    题目描述 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后把石子全部取完 ...

  4. ●BZOJ 2007 NOI 2010 海拔

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2007 题解: 网络流.最小割.对偶图 奇妙的题 ~ 种种原因导致了高度要么为 0,要么为 1 ...

  5. [bzoj4813][Cqoi2017]小Q的棋盘

    来自FallDream的博客,未经允许,请勿转载,谢谢. 小Q正在设计一种棋类游戏.在小Q设计的游戏中,棋子可以放在棋盘上的格点中.某些格点之间有连线,棋子只能在有连线的格点之间移动.整个棋盘上共有V ...

  6. 常用SQL Server命令(持续) | Commonly used SQL Server command list (Cont')

    ---------------------------------------------------- 1. 查看某数据库中某表详细信息 SP_HELP USE DB_NAME GO SP_HELP ...

  7. oracle安装过程和创建本地数据库

    环境: win7 64位 工具: PLSQL Developer 百度云下载:链接:https://pan.baidu.com/s/14L3VCG8YwHzpdhEN7ama0w 密码:jlre or ...

  8. JavaScript和DOM

    body { margin: 0 } .left { float: left } .right { float: right } .pg-head { height: 48px; background ...

  9. 美团java后台实习三面

    美团一面(50分钟) 1.spring的理解. 1.项目相关 2.Redis缓存的应用 3.http解析的全过程 4.Java中的锁 5.Hashmap和concurrenthashMap源码 6.死 ...

  10. 更改计算机名及使用Secure CRT ssh连接用户添加方法汇总

    修改计算机名 更改/etc/sysconfig下的network文件,在提示符下输入vi /etc/sysconfig/network,然后将HOSTNAME后面的值改为想要设置的主机名.  开启SS ...