关于RxJava防抖操作
2016-05-18 10:41
381 查看
关于RxJava防抖操作
在实际开发中为了防止用户手抖点开两个重复的界面,我们会做防抖处理。(这里吐槽一下微信,快速点击朋友圈就可以点开多个页面。。。)解决的老办法我就不介绍了,这里我们主要说说利用RxJava来实现。1.利用throttleFirst操作符
这里用到了Jake Wharton大神的RxBinding库。代码大同小异,如下:(取1秒内的第一次点击响应。)
RxView.clicks(button) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Observer<Object>() { @Override public void onCompleted() { log.d ("completed"); } @Override public void onError(Throwable e) { log.e("error"); } @Override public void onNext(Object o) { log.d("button clicked"); } });
但是这里有一点需要注意,也是自己学习时遇到的一个坑。Github上有这样一个项目RxJavaSamples,这位作者收集了一些RxJava使用场景的例子,其中有ButtonClicksFragment这个类。源代码如下:
public class ButtonClicksFragment extends BaseFragment { @Bind(R.id.btn_click) Button btnClick; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_button_clicks, container, false); ButterKnife.bind(this, view); return view; } @OnClick(R.id.btn_click) public void btnClick(){ RxView.clicks(btnClick) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Observer<Object>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Object o) { Toast.makeText(getContext(),"Click",Toast.LENGTH_SHORT).show(); } }); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } }
代码很简单,乍得一看没有问题。但实际运行后,我们发现点击Button的第一次没有出现Toast,之后点击正常。这是为什么呢?
我们可以看看RxBinding的源码。
@CheckResult @NonNull public static Observable<Object> clicks(@NonNull View view) { return Observable.create(new ViewClickOnSubscribe(view)); }
final class ViewClickOnSubscribe implements Observable.OnSubscribe<Object> { private final Object event = new Object(); private final View view; ViewClickOnSubscribe(View view) { this.view = view; } @Override public void call(final Subscriber<? super Object> subscriber) { checkUiThread(); View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { if (!subscriber.isUnsubscribed()) { subscriber.onNext(event); } } }; view.setOnClickListener(listener); subscriber.add(new MainThreadSubscription() { @Override protected void onUnsubscribe() { view.setOnClickListener(null); } }); } }
发现其实内部实现很简单,就是直接用一个包裹着的
setOnClickListener()来实现的,同时点击监听转换成
Observable返回。同时我们也明白了问题所在,当我们第一次点击的时候,这个防抖的监听才注册上,以后点击时,有了防抖的监听,所以后面点击正常了。那么如何解决这个问题呢?很简单,换个位置。
public class ButtonClicksFragment extends BaseFragment { @Bind(R.id.btn_click) Button btnClick; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_button_clicks, container, false); ButterKnife.bind(this, view); RxView.clicks(btnClick) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Observer<Object>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Object o) { Toast.makeText(getContext(),"Click",Toast.LENGTH_SHORT).show(); } }); return view; } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } }
当然防抖操作也可以用其他操作符实现(比如debounce),根据具体情况定。
2.多控件组合防抖
上面我们讲到的情况主要是单控件防抖,可是有时页面上有多个控件都需要添加防抖操作,同时执行效果一样。比如在我们的项目中有个遥控器界面,我们不仅要做到每一个按钮的防抖,还要做到单位时间内快速点击多个按钮的防抖,这时我们怎么做?如果用上面的方法,只是能做到每个独立按钮的防抖,但是多个按钮就没办法了。这里我提供一下我的实现方法,仅供参考。使用
ButterKnife一般多个控件的点击事件可以如下:
@OnClick({R.id.iv_hz_jb_kg, R.id.iv_hz_jb_cd, R.id.iv_hz_jb_jiay, R.id.iv_hz_jb_jiany, R.id.iv_jb_ok, R.id.iv_jb_xx, R.id.iv_jb_yy, R.id.iv_jb_ss, R.id.iv_jb_zz}) public void onClick(View view) { switch (view.getId()) { case R.id.iv_hz_jb_kg: break; case R.id.iv_hz_jb_cd: break; case R.id.iv_hz_jb_jiay: break; case R.id.iv_hz_jb_jiany: break; case R.id.iv_jb_ok: break; case R.id.iv_jb_xx: break; case R.id.iv_jb_yy: break; case R.id.iv_jb_ss: break; case R.id.iv_jb_zz: break; } }
如果这里我们使用
RxBinding如下:
@OnClick({R.id.iv_hz_jb_kg, R.id.iv_hz_jb_cd, R.id.iv_hz_jb_jiay, R.id.iv_hz_jb_jiany, R.id.iv_jb_ok, R.id.iv_jb_xx, R.id.iv_jb_yy, R.id.iv_jb_ss, R.id.iv_jb_zz}) public void onClick(final View view) { RxView.clicks(view) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Action1<Void>() { @Override public void call(Void aVoid) { switch (view.getId()) { case R.id.iv_hz_jb_kg: break; case R.id.iv_hz_jb_cd: break; case R.id.iv_hz_jb_jiay: break; case R.id.iv_hz_jb_jiany: break; case R.id.iv_jb_ok: break; case R.id.iv_jb_xx: break; case R.id.iv_jb_yy: break; case R.id.iv_jb_ss: break; case R.id.iv_jb_zz: break; } } });
实际执行效果没有问题,但是会出现最开始我们说到的问题,就是第一次点击没反应。那怎么办呢?
其实
RxBinding在内部去添加监听与
ButterKnife的监听“重复”了,所以我们可以自己实现
RxBinding效果,不在内部添加监听。如下:
@OnClick({R.id.iv_hz_jb_kg, R.id.iv_hz_jb_cd, R.id.iv_hz_jb_jiay, R.id.iv_hz_jb_jiany, R.id.iv_jb_ok, R.id.iv_jb_xx, R.id.iv_jb_yy, R.id.iv_jb_ss, R.id.iv_jb_zz}) public void onClick(final View view) { Observable.create(new Observable.OnSubscribe<View>(){ @Override public void call(Subscriber<? super View> subscriber) { subscriber.onNext(view); } }) .buffer(500, TimeUnit.MILLISECONDS) // 缓存0.5s内的点击 .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<List<View>>() { @Override public void call(List<View> list) { if(list.size() == 0){ return; } View view = list.get(list.size() - 1);// 只响应0.5秒内按的最后一次点击事件 switch (view.getId()) { case R.id.iv_hz_jb_kg: break; case R.id.iv_hz_jb_cd: break; case R.id.iv_hz_jb_jiay: break; case R.id.iv_hz_jb_jiany: break; case R.id.iv_jb_ok: break; case R.id.iv_jb_ss: break; case R.id.iv_jb_zz: break; case R.id.iv_jb_xx: break; case R.id.iv_jb_yy: break; default: break; } } });
那么这样问题就解决了。我将0.5秒内的所有点击,只执行最后一次。
PS : 以上只是一种实现思路,有更好的方法希望可以告诉我,抛砖引玉一下。喜欢的点个赞哦!
相关文章推荐
- java学习 Controller小记
- java基础知识:继承
- 《学习笔记》之JAVA设计模式--简单工厂模式
- 关于Java多线程实现生产者和消费者的问题
- Struts2工作原理
- eclipse rebase w/merge
- 160518、java中使用百度地图(超级简单)
- Java_Java Compiler 应用实例
- Rxjava中toList操作符
- java web 监听器listener
- javadoc解决中文乱码问题
- spring源码分析(一)- 源码下载和导入eclipse
- C# 实现java中 wiat/notify机制
- 为什么Java中字符串是不可变的
- MyEclipse如何对Hibernate进行逆向工程
- 代码获取spring管理的javabean
- 安装winPcap和jpcap
- java实现在线预览--poi实现word、excel、ppt转html
- Unresolved inclusion: <jni.h>
- java枚举常用场景小结