使用Retrofit搜索api

时间:2016-04-29 07:56:40

标签: android retrofit rx-java

我需要在我的Android应用中实现搜索功能。 API不是一个合适的搜索API,它就像这样

https://example.com/api/list/photos/?start=0&end=30&search=something

所以,基本上,我必须查询每个搜索查询字母的后端,并且端点是分页的,这样我就可以控制要显示的条目数。

我阅读some code使用RxJava为搜索添加时间限制约束,这样我至少可以减少对后端的调用次数。但是我面临的问题是,如果我输入's'请求,如果我输入'so',那么另一个请求就会消失(假设我输入有延迟),所以我可能会得到结果由于某种原因's'之前的'so'然后整个搜索将被打破。此外,如果已经提出请求,响应将在某个时刻到来,我将需要根据该响应更改UI,即使这不是我想要搜索的最终查询。

我正在使用Retrofit 1.9,每当我收到回复时,我都会根据结果更新recyclerView。有没有办法根据上述情况取消Retrofit请求?使这个东西正常工作的最佳设计或实现是什么?任何帮助将受到高度赞赏。

编辑:这是我自己编写的内容。如果能以任何方式改进,请告诉我。

Subscription subscription = RxTextView.textChangeEvents(inputSearch)
                .debounce(400, TimeUnit.MILLISECONDS)// default Scheduler is Computation
                .filter(new Func1<TextViewTextChangeEvent, Boolean>() {
                    @Override
                    public Boolean call(TextViewTextChangeEvent changes) {
                        return !TextUtils.isEmpty(inputSearch.getText().toString());
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(getSearchObserver());


private void getSearchResults(String s) {
        LogUtil.i(TAG, "getSearchResults called");
        indicator.setVisibility(View.VISIBLE);
        DiscoverAPI discoverAPI = restAdapter.create(DiscoverAPI.class);
        discoverAPI.getSearchResults(0, 10, s, new Callback<List<Result>>() {
            @Override
            public void success(List<Result> results, Response response) {
                LogUtil.i(TAG, "discover api successful");
                list.clear();
                if (adapter != null) {
                    adapter.notifyDataSetInvalidated();
                }
                list.addAll(results);
                if (adapter == null) {
                    adapter = new SearchGalleryAdapter(TestActivity.this, list);
                    listView.setAdapter(adapter);
                } else {
                    adapter.notifyDataSetChanged();
                }
                indicator.setVisibility(View.GONE);
            }

            @Override
            public void failure(RetrofitError error) {
                LogUtil.i(TAG, "discover api failed");
            }
        });
    }

2 个答案:

答案 0 :(得分:1)

你可以尝试这样的事情:

 RxTextView.afterTextChangeEvents(mTextView)
        .map(new Func1<TextViewAfterTextChangeEvent, String>() {
            @Override
            public String call(TextViewAfterTextChangeEvent textViewAfterTextChangeEvent) {
                return textViewAfterTextChangeEvent.editable().toString();
                }
        })
        .switchMap(new Func1<String, Observable<SearchResponse>>() {
            @Override
            public Observable<SearchResponse> call(String query) {
                return mApiService.search(query);
            }
        })
  • afterTextChangeEvents TextView
  • 上创建文本更改事件流
  • map TextViewAfterTextChangeEvent 映射到已键入的 String
  • switchMap 的工作原理与 flatMap 类似,因此它会将您的事件映射到另一个事件流(在本例中为Api请求),但是,在发出另一个事件后,它取消订阅上一个流(因此将忽略之前的Api请求结果)

答案 1 :(得分:1)

最后,我找到了解决方案,所以在此发帖以供参考。

RxTextView.textChangeEvents(inputSearch)
                .debounce(400, TimeUnit.MILLISECONDS)
                .map(new Func1<TextViewTextChangeEvent, String>() {
                    @Override
                    public String call(TextViewTextChangeEvent textViewTextChangeEvent) {
                        return  textViewTextChangeEvent.text().toString();
                    }
                })
                .switchMap(new Func1<String, Observable<List<Result>>>() {
                    @Override
                    public Observable<List<Result>> call(String s) {
                        DiscoverAPI discoverAPI = restAdapter.create(DiscoverAPI.class);
                        return discoverAPI.getRxSearchResult(0, 9, s);
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(getRxSearchObserver());


private Observer<List<Result>> getRxSearchObserver() {
        return new Observer<List<Result>>() {
            @Override
            public void onCompleted() {
                LogUtil.i(TAG, "onCompleted called");
            }

            @Override
            public void onError(Throwable e) {
                LogUtil.i(TAG, "onError called");
            }

            @Override
            public void onNext(List<Result> results) {
                LogUtil.i(TAG, "onNext called");
                list.clear();
                if (adapter != null) {
                    adapter.notifyDataSetInvalidated();
                }
                list.addAll(results);
                if (adapter == null) {
                    adapter = new SearchGalleryAdapter(TestActivity.this, list);
                    listView.setAdapter(adapter);
                } else {
                    adapter.notifyDataSetChanged();
                }
                indicator.setVisibility(View.GONE);
            }
        };
    }

希望它有所帮助。