Rxjava应用(1)_去View抖动

匿名 (未验证) 提交于 2019-12-02 21:53:52

最近项目里有个点赞的功能需求,发现当用户对一条评论反复点赞的速度过快时,会引起轻微的数据错乱。对一条评论不停的点赞,评论数本应在+1-1之间不断循环的,但是点赞/取消点赞的时候需要进行网络请求,将点击结果上传到服务器,所以点多了之后,由于延时的原因,会出现某些+1-1操作会失效,具体表现为,对一个初始赞数为0的评论进行这样一波疯狂操作后,点赞总数有可能变成负数,这无疑是不允许的。

至于要问有什么用户会这么无聊,跟打地鼠一样疯狂点赞,那当然非我们的测试小哥莫属了。

思考了各种解决方案的优劣后,最终采用了最省事的一个方法,给点赞按钮加个抖动阈值。正好最近写 RxJava 写得不亦乐乎,再加上不想为了这一处地方就引入 RxBinding 库,就想着自己写一下,于是顺手就写出了以下代码用以去除点击抖动:

mBinding.title.setOnClickListener(v -> {             Observable.create(e -> e.onNext(new Object()))                     .throttleFirst(600, TimeUnit.MILLISECONDS)                     .subscribe(o -> {                         // 进行取消点赞或点赞的网络请求                     });         });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

自己也没测就直接交给测试小哥了,然后被暴击:“你特么怎么该都没改就给我测了,这表现和之前没区别啊!?”

于是我瞬间懵比,自己一测,确实没解决问题,在代码里面写了俩 Log 一瞧,这去抖动根本没起任何作用啊,然后又找了网上几篇直接用 RxJava 实现的点击去抖动功能,发现我这也没写错啊。

左思右想,最后去看了下 RxBinding 的源码,才发现问题的关键所在。去抖动,需要将点击事件这个“事件”转换成一个Observable对象,而瞧我上面那段代码,直接在点击事件里生成的一个Observable对象,导致的结果就是每点击一次,就产生了一个新的 RxJava 流,所以导致没有达到想要的“只取600ms内第一次点击”的效果。

思考了下,转换成如下写法,总算达成效果了。

Observable.create((ObservableOnSubscribe<View>) e ->                 mBinding.title.setOnClickListener(v -> e.onNext(v))         )                 .throttleFirst(600, TimeUnit.MILLISECONDS)                 .subscribe(view -> {                     // 进行取消点赞或点赞的网络请求                 });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

虽然 RxBinding 这个库也比较好用,但是我们的自定义控件好像就用不上它的,所以还是只能自己来实现去抖动了。

用 RxJava 实现的点击取抖动虽好,但有些情况还是顾不到,用它实现去抖动,就必须获取它的点击事件,将之转换成Observalbe对象才行,但有些情况这样是行不通的,比如一个页面的批量点击功能的实现:

public void onViewClicked(View view) {     switch (view.getId()) {         case R.id.check_for_update_button:             break;         case R.id.clear_cache_button:             break;         case R.id.save_flow_toggle:             break;         case R.id.feedback_button:             break;         case R.id.logout_button:             break;         default:     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这个里面就根本没法获取到点击事件对象,所以要么将这些控件单独拿出来一个个实现,要么就用土办法,在上次点击后一定时间内让点击事件无效化,可以用如下代码:

private static final int CLICK_INTERVAL = 600; private static long lastClickTime;  public static boolean clickValid() {     long currentClickTime = System.currentTimeMillis();     return currentClickTime - lastClickTime > CLICK_INTERVAL; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果只需要上述所有点击事件共用一个抖动时间,那么将上面这段代码写入统一的工具类,并在switch语句之前调用即可,也可以个性化定制每个View的抖动时间,那就写起来麻烦一点。在我看来是个“傻大黑粗”的方法。

转载请标明出处:Rxjava应用(1)_去View抖动
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!