【问题标题】:How can I send only last requst with Rx and Retrofit?如何使用 Rx 和 Retrofit 仅发送最后一个请求?
【发布时间】:2017-07-19 02:33:05
【问题描述】:

我有一个 EditText 视图和 TextWatcher,在 onTextChanged 方法中,我必须请求服务器从 EditText 字段查询结果。 在我的演示者中,我为此使用 rx,但我需要延迟搜索,直到用户输入结束。此刻我得到了这个:

service.getData(query)
            .delaySubscription(REQUEST_DELAY_FROM_SERVER, TimeUnit.MILLISECONDS, Schedulers.io())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                    data-> {
                        getViewState().showData(data);
                    },
                    error -> {
                        Log.e(this.getClass().getSimpleName(), error.getMessage(), error);
                    }
            );

但 delaySubscription 无法按预期工作。它收集所有呼叫,并在延迟后发送每个呼叫。当只发送一次请求时,我必须像使用 handler.postDelayed() 一样做同样的事情。

【问题讨论】:

    标签: android retrofit rx-java rx-android


    【解决方案1】:

    编辑 2:

    RxJava2

    中的演示者
    class Presenter {
        private PublishSubject<String> queryPublishSubject = PublishSubject.create();
    
        public Presenter() {
            queryPublishSubject
                    .debounce(1000, TimeUnit.MILLISECONDS)
                    // You might want to skip empty strings
                    .filter(new Predicate<CharSequence>() {
                        @Override
                        public boolean test(CharSequence charSequence) {
                            return charSequence.length() > 0;
                        }
                    })
                    // Switch to IO thread for network call and flatMap text input to API request
                    .observeOn(Schedulers.io())
                    .flatMap(new Function<CharSequence, Observable<...>() {
                        @Override
                        public Observable<...> apply(final CharSequence charSequence) {
                            return ...; // Call API
                        }
                    })
                    // Receive and process response on Main thread (if you need to update UI)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(...);
        }
    
        public void onSearchTextChanged(String query) {
            queryPublishSubject.onNext(query);
        }
    }
    

    编辑 1:

    RxJava 1中的相同代码:

    class Presenter {
        private PublishSubject<String> queryPublishSubject = PublishSubject.crate();
    
        public Presenter() {
            queryPublishSubject
                .debounce(1000, TimeUnit.MILLISECONDS)
                // You might want to skip empty strings
                .filter(new Func1<CharSequence, Boolean>() {
                    @Override
                    public Boolean call(CharSequence charSequence) {
                        return charSequence.length() > 0;
                    }
                })
                // Switch to IO thread for network call and flatMap text input to API request
                .observeOn(Schedulers.io())
                .flatMap(new Func1<CharSequence, Observable<...>() {
                    @Override
                    public Observable<...> call(final CharSequence charSequence) {
                        return ... // Call API
                    }
                })
                // Receive and process response on Main thread (if you need to update UI)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(...);
        }
    
        public void onSearchTextChanged(String query) {
            queryPublishSubject.onNext(query);
        } 
    }  
    

    初步答案(使用 RxBinding 和 RxJava 1)

    正确的答案是使用Debounce,但除此之外还有一些您可能会发现有用的技巧

    textChangeListener = RxTextView
        .textChanges(queryEditText)
        // as far as I know, subscription to textChanges is allowed from Main thread only
        .subscribeOn(AndroidSchedulers.mainThread()) 
        // On subscription Observable emits current text field value. You might not need that
        .skip(1) 
        .debounce(1000, TimeUnit.MILLISECONDS)
        // You might want to skip empty strings
        .filter(new Func1<CharSequence, Boolean>() {
            @Override
            public Boolean call(CharSequence charSequence) {
                return charSequence.length() > 0;
            }
        })
        // Switch to IO thread for network call and flatMap text input to API request
        .observeOn(Schedulers.io())
        .flatMap(new Func1<CharSequence, Observable<...>() {
            @Override
            public Observable<...> call(final CharSequence charSequence) {
                return ... // Call API
            }
        })
        // Receive and process response on Main thread (if you need to update UI)
        .observeOn(AndroidSchedulers.mainThread())
    

    【讨论】:

    • 如何在我的presenter类中实现这个逻辑?
    • 你从哪里得到query
    • 我用 TextWatcher 实现了 Fragment。简单的 EditText 视图和方法@Override public void onTextChanged(CharSequence s, int start, int before, int count) { presenter.onSearchTextChanged(String.valueOf(s)); } 和 presnter 实现来自主题的逻辑
    • Func1 到底是什么,因为 android studio 找不到 Func1 类,尽管我包含了所有需要的 rx 依赖项
    • 嗨! @AbdulmalekDery,我已经用 RxJava 2 代码示例更新了答案。最初的答案是使用 RxJava 1。希望这可行
    【解决方案2】:

    我有类似的地址研究,结合 RxAndroid 可以给出类似的结果:

     RxTextView.textChanges(searchEditText)
                            .debounce(100, TimeUnit.MILLISECONDS)
                            .subscribe(....);
    

    debounce 操作符在这种情况下将等待 observable 停止发出 100 毫秒,然后再发出下一个值。

    【讨论】:

    • 如何在我的演示者类中实现这一点?或者它只适用于 RxTextView?
    【解决方案3】:

    尝试使用 debounce 代替。例如。下面的代码查找 TextView 中的更改,并在发生更改但去抖动为 100 毫秒时执行某些操作

    RxTextView
    .textChanges(queryEditText)
    .debounce(100, TimeUnit.MILLISECONDS)
    .doOnNext(new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
    
        }
    })
    .subscribe();
    

    【讨论】:

    • 只有在我有 RxTextView 的情况下才有效?我不能只用一个方法调用来做同样的事情吗?我需要尝试在我的 Presenter 类中执行此逻辑。现在它像@Override public void onTextChanged(CharSequence s, int start, int before, int count) { presenter.onSearchTextChanged(String.valueOf(s)); } 一样工作,并且 presnter 实现了来自主题的逻辑
    • 我所做的方式是,在我看来,我有一个方法返回 return RxTextView.textChanges(queryEditText);所以在演示者中,我正在调用 view.queryTextObservable().debounce().doOnNext().subscribe()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    相关资源
    最近更新 更多