【问题标题】:RxAndroid: Observe an EditText while also observing touches on 2 ViewsRxAndroid:观察一个 EditText,同时观察对 2 个视图的触摸
【发布时间】:2016-07-08 06:24:32
【问题描述】:

让我为一项需要我花费数天时间才能完成的小任务动脑筋......

我有一个 EditText,用户将输入一个字符串,该字符串将用于进行 Wikipedia 搜索并将结果提供给 ListView。 EditText 应该有 1 秒的限制,并且必须进行过滤才能检查“不适当”字符串列表。如果输入在该字符串列表中,则搜索不会通过,除非用户同时触摸在屏幕的 2 个角上找到的 2 个隐藏视图,否则它将跳过此检查。

这里有一些sn-ps可以帮助你理解我已经拥有的......

// a list of inappropriate content
private static String[] INAPPROPRIATE_CONTENT = {
            "test"
        };

// subscription to the touches happening on hidden view #1
Subscription subSecretLeft = RxView.touches(vSecretLeft)
        .filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
        .subscribe(motionEvent -> secretLeftClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);

// subscription to the touches happening on hidden view #2
RxView.touches(vSecretRight)
        .filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
        .subscribe(motionEvent -> secretRightClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);

// subscription to the EditText
RxTextView.textChanges(etxtSearchFilter)
        .throttleLast(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
        .map(c -> c.toString().trim())
        .filter(s -> !(s.isEmpty() || isInappropriate(s)))
        .subscribe(s -> fetchWikiSearch(s));

其中 isInappropriate(String s) 是检查是否在数组中找到术语的方法,而 fetchWikiSearch(String s) 执行搜索并填充 ListView。

我尝试了几种方法,最后能想到的方法如下:

Observable.zip(
        Observable.combineLatest(
                RxView.touches(vSecretLeft)
                        .filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
                RxView.touches(vSecretRight)
                        .filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
                (ev1, ev2) -> ev1.getAction() == MotionEvent.ACTION_DOWN && ev2.getAction() == MotionEvent.ACTION_DOWN
        ).asObservable(),
        RxTextView.textChanges(etxtSearchFilter)
                .throttleLast(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
                .map(c -> c.toString().trim())
                .filter(s -> !s.isEmpty()),
        (overrideFilter, s) ->
                overrideFilter || !isInappropriate(s) ? s : "BLOCKED"
).subscribe(s -> Log.i("ObservableZip", "s: " + s));

但显然,只要我不触及这些视图,它就不会发出任何东西。甚至 Observable.combileLatest() 也不能很好地工作,因为只有当两个视图都获得 MotionEvent.ACTION_DOWN 时它才会发出...

如果您有任何提示或实际解决方案,请随时发表评论。谢谢。

【问题讨论】:

    标签: java android rx-java rx-android reactivex


    【解决方案1】:

    这还不够吗?

    Observable.combineLatest(
            RxView.touches(vSecretLeft)
                    .filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
            RxView.touches(vSecretRight)
                    .filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
            RxTextView.textChanges(etxtSearchFilter)
                    .debounce(1, TimeUnit.SECONDS)
                    .map(c -> c.toString().trim())
                    .filter(s -> !s.isEmpty()),
            (motionEventLeft, motionEventRight, entered) -> {
                boolean overrideFilter = motionEventLeft.getAction() == MotionEvent.ACTION_DOWN && motionEventRight.getAction() == MotionEvent.ACTION_DOWN;
                return overrideFilter || !isInappropriate(entered) ? entered : "BLOCKED";
            })
            .subscribe(s -> Log.i("ObservableCombineLatest", "s: " + s));
    

    (我还将throttleLast 更改为debounce,因为这样做感觉更好)

    编辑

    Observable.combineLatest(
            RxView.touches(vSecretLeft)
                    .map(motionEvent -> motionEvent.getAction())
                    .filter(action -> action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)
                    .startWith(MotionEvent.ACTION_UP),
            RxView.touches(vSecretRight)
                    .map(motionEvent -> motionEvent.getAction())
                    .filter(action -> action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)
                    .startWith(MotionEvent.ACTION_UP),
            RxTextView.textChanges(etxtSearchFilter)
                    .debounce(1, TimeUnit.SECONDS)
                    .map(c -> c.toString().trim())
                    .filter(s -> !s.isEmpty()),
            (leftAction, rightAction, entered) -> {
                boolean overrideFilter = leftAction == MotionEvent.ACTION_DOWN && rightAction == MotionEvent.ACTION_DOWN;
                return overrideFilter || !isInappropriate(entered) ? entered : "BLOCKED";
            })
            .subscribe(s -> Log.i("ObservableCombineLatest", "s: " + s));
    

    【讨论】:

    • 感谢您的回复,我也尝试过,但整个 Observable 只有在第 2 个 Observables 也这样做时才会发出一些东西。所以,如果我写“测试”,我需要接触这两个视图才能得到结果。我需要的是,如果它不合适,它能够发出用 'BLOCKED' 更改的文本,但如果两个视图都被触及,则跳过 isInappropriate() 部分。
    • 你写的东西并不完全正确:“只有当两个第一个 Observables 也这样做时,Observable 才会发出一些东西”。 combineLatest 作为根转换(而不是 zip)的全部目的是,如果 任何 它们发出一些东西,它就会发出。但我确实看到了一个小问题,您需要确保前两个 observables 发出任何东西,以便 combineLatest 完全按预期工作(在任何可观察组件发出时发出)。这两个与触摸相关的可观察对象必须发出它们的初始状态。稍后我会尝试更新我的答案。
    • @jpmastermind 我更新了答案,请随时查看
    • 太棒了,它正在工作!非常感谢你!实际上,我仍在学习 Rx,感谢您澄清这一点,@bartek-lipinski。 :)
    【解决方案2】:

    您似乎走在正确的轨道上,但您可能希望使用 startsWith 即“初始化”您的隐藏视图

    // subscription to the touches happening on hidden view #1
    Subscription subSecretLeft = RxView.touches(vSecretLeft)
            .filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
            .startsWith(MotionEvent.ACTION_UP)
            .subscribe(motionEvent -> secretLeftClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);
    

    【讨论】:

      猜你喜欢
      • 2018-01-29
      • 2011-06-17
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-05
      • 1970-01-01
      相关资源
      最近更新 更多