【问题标题】:RxJava - how to invoke subscriber on 4 click events in AndroidRxJava - 如何在 Android 中的 4 个点击事件上调用订阅者
【发布时间】:2016-01-19 15:51:20
【问题描述】:

在 android 中,我有一个这样定义的文本视图:

<TextView
     android:id="@+id/text1"       
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="@string/hello_world"
     android:textColorHighlight="#000000"
     android:textIsSelectable="true" />

我的目标是点击4次后,我想开始一个新的活动。我需要用 RXJava 来做这件事;这是一个要求。或者rxAndroidrxBinding等。

我的活动如下所示:

public class MainActivity extends Activity implements onClickListener {
    TextView tv;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv=(TextView)findViewById(R.id.text1);
        tv.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.text1){

        }
    }
}

更新: 但这只是标准的做法。必须有办法使用响应式 rxJava API。

所以我读到我们可以这样做:

RxView.clicks(tv).flatMap(tv -> { 
        // another observable which can throw onError. 
        return Observable.error(null); 
    }).subscribe(object -> { 
        Log.d("CLICK", "textview clicked", start activity);
    }, error -> { 
        Log.d("CLICK", "ERROR");
    });

我能否以某种方式使用rxBinding 中的命令使其仅在单击 4 次后执行?我不希望存储静态变量,或使用匿名类并在其中存储成员变量以供计数。应该有一个可观察的方法。

【问题讨论】:

  • 您正在尝试实现四次点击或仅点击 4 次,并且它们之间的时间未指定?
  • 四次点击,但我可以接受 4 次点击,但有时间限制。效果一样好。

标签: android rx-java rx-android


【解决方案1】:

您可以通过以下方式实现:

Observable.create((Observable.OnSubscribe<Void>) subscriber -> {
    if (!subscriber.isUnsubscribed()) {
        button.setOnClickListener(v -> subscriber.onNext(null));
    }
}).buffer(1000, TimeUnit.MILLISECONDS)
        .filter(clicks -> clicks.size() == 4)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(clicks -> {
            Log.d("CLICK", "CLICK");
        });
  • buffer() - 为 1 秒的窗口收集点击次数
  • filter() - 过滤所有发出的缓冲项,其中缓冲区中的项数不等于 4(禁用双、三、五次点击)

最难的部分是指定缓冲时间“窗口”。一秒钟有时是不够的,但在其他情况下,用户必须等待几毫秒。

【讨论】:

  • 什么是“create((Observable.OnSubscribe”?我正在使用 rxjava2
  • @PabloCegarra 这是基于 RxJava1 的示例。方法 create() 用于,当您需要从某个提供者(在这种情况下为 OnClickListener)创建 observable 时。 Observable.OnSubscribe&lt;Void&gt; 只是订阅者的类型定义。在 RxJava2 中你应该使用Flowable
  • 你能把你的帖子更新到 rxjava2 吗?如果它有效,我会投票给你,现在我使用 rxbinding 只是为了这个
  • @PabloCegarra 请创建一个新问题并在此处指定您的要求。有人看一下。
【解决方案2】:

您可以创建一个 observable 以在每次单击按钮时发出,然后计算它发出的总次数,并使用过滤器,以便您的订阅者只有在发出四次后才能看到它。

Observable<View> buttonObservable = ViewObservable.clicks(initiateButton, false);
buttonObservable.count()
        .filter(count -> (count >= 4))
        .subscribe(object -> {
            //Your code here
        });

【讨论】:

  • Observable.count 方法只返回Observable 发出项目的次数。它是 RxJava 的一部分
  • count 不能在这里使用,因为它只会在可观察的发射完成后发射一个项目(rxmarbles.com/#count)另一方面,可观察的点击是无限的
【解决方案3】:

对于检测具有合理超时的多次点击(例如,在 1000 毫秒内点击 4 次),以下方法效果很好:

    final int numClicks = 4;
    final int timeout = 1000;
    disposables.add(RxView.clicks(tv)
            .buffer(timeout, TimeUnit.MILLISECONDS, numClicks)
            .filter(list -> list.size() == numClicks)
            .subscribe(this::doThing));

在此示例中,buffer 将发出 4 个事件,或者每 1000 毫秒发出少于 4 个事件,由于filter,这将被忽略

【讨论】:

  • 这个很好,谢谢,但不是和Zygi回答一样吗?
  • 我最初尝试了那个,但我无法让它工作。即使它确实有效,这个答案对我来说也有几个好处:1。你可以在一行中完成; 2.buffer的版本,包括超时和numClicks,非常适合“多次点击”场景
  • @Peter 这将等待一秒钟完成,然后再给出结果。如果我想在 1 秒的时间范围内完成 4 次点击后立即获得结果怎么办?
  • @RishabhJain 你确定吗?根据buffer 的文档,当达到timespan(上面示例中的超时)或达到count(上面的numClicks)时,将发出这些项目 - 因此,当在上面的示例中收到4次点击时无论经过多少时间,都应该调用观察者:reactivex.io/documentation/operators/buffer.html
【解决方案4】:

@skywall 答案是最完整的,但是如果您不关心时间间隔,最简单的答案是使用skip

Observable<Void> fourClicksView = RxView.clicks(tv).skip(3); 
fourClicksView.subscribe(...);

【讨论】:

  • 这取决于您是否需要恰好 4 次点击而不是更多。问题已完全按照四次点击进行说明。
  • 必选题4,当然可以随意改,如果只想要一个事件也可以用first()或者take(1)之后
【解决方案5】:

使用缓冲和去抖动运算符。

val clickStream = RxView.clicks(view)
    clickStream.buffer(clickStream.debounce(250, TimeUnit.MILLISECONDS))
            .map { it.size }
            .filter { it == 4 }
            .subscribe({
            })

【讨论】:

【解决方案6】:

如果你想在一个时间窗口内点击一定次数后开始一个活动,那么试试这个:

RxView.clicks(tv)
    .map(e -> SystemClock.elapsedRealtime())
    .buffer(NUM_CLICKS, 1) //Grab every sub-sequence of however many clicks
    .filter(times -> times.size() == NUM_CLICKS) //Last values will be truncated
    .filter(times -> times.get(NUM_CLICKS - 1) - times.get(0) < ALLOWED_TIME) //check times
    .subscribe(ignore -> startActivity());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    相关资源
    最近更新 更多