RxJavaを使用した検索の実装

この記事では、RxJava for Androidを使用した最適でコンパクトな検索の実装について説明し、不要な結果を排除し、無駄なネットワーク呼び出しの数を減らします。



検索例

オリジナルは2017年10月16日に作成されました。翻訳は無料です。



現在、私たちが毎日使用しているアプリケーションのほとんどは、すばやく検索する機能を提供しています。 したがって、検索の実装は重要なタスクです。 開発者として、検索をより良い方法で実装することが重要です。



RxJavaを使用して最適な方法で検索を実装する方法を見てみましょう。 RxJavaにはすべての演算子があります



個人的には、RxJavaを使用すると、RxJavaを使用しないと非常に困難な問題を非常に簡単に解決できると考えています。 RxJavaは素晴らしい技術です。



検索を実装するために使用するRxJava要素を見てください。





始めましょう



まず、SearchViewを観察可能にする必要があります。 PublishSubjectを使用して作成しましょう。 AndroidからSearchViewを使用しています。 ビューは、EditTextのような機能を持つものであれば何でもかまいません。 observableを実装するには、フィールドのテキストを変更するリスナーを実装する必要があります。



public class RxSearchObservable { public static Observable<String> fromView(SearchView searchView) { final PublishSubject<String> subject = PublishSubject.create(); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String s) { subject.onComplete(); return true; } @Override public boolean onQueryTextChange(String text) { subject.onNext(text); return true; } }); return subject; }
      
      



ConstOrVarからの注意

SearchViewのObservableは正しく機能しません。 onCreate()でサブスクライブしますが、onQueryTextSubmit()がトリガーされると、onCompleteが呼び出されるため、サブスクライブ解除されます。 繰り返しの検索が機能しないことが判明しました。 繰り返し検索を機能させるには、subject.onComplete()を取り除く必要があります。

ScrobotBFSからの注意:

Subjectは使用しないでください。1つの目的のためにのみ存在します。命令型と反応型を組み合わせるためです。 Observable.create()を使用することをお勧めします。 Backpressureについて考える必要があるのはまさに検索です。今日ほとんどの人がRxJava2を使用しているので、Flowableを使用してこの問題を解決します。

次に、以下の例のように、作成したメソッドを呼び出して、オペレーター呼び出しを追加する必要があります。



 RxSearchObservable.fromView(searchView) .debounce(300, TimeUnit.MILLISECONDS) .filter(new Predicate<String>() { @Override public boolean test(String text) throws Exception { if (text.isEmpty()) { return false; } else { return true; } } }) .distinctUntilChanged() .switchMap(new Function<String, ObservableSource<String>>() { @Override public ObservableSource<String> apply(String query) throws Exception { return dataFromNetwork(query); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<String>() { @Override public void accept(String result) throws Exception { textViewResult.setText(result); } });
      
      





次に、これらの演算子が使用される理由と、それらがどのように連携するかについて説明します。



デバウンス



時間パラメータはこの演算子に渡されます。 この場合、たとえば「a」、「ab」、「abc」などのテキストのユーザー入力のイベントをキャッチします。 多くの場合、入力は非常に迅速に行われ、これには多くのネットワーク呼び出しが伴います。 ただし、ユーザーは通常、「abc」の結果にのみ関心があります。 そのため、「a」、「ab」のクエリの実行をドロップする必要があります。 デバウンスステートメントは急いで救助に行きます。 パラメーターで渡された時間の間、ユーザーが非アクティブであることを想定しています。 待機中に入力が行われると、待機カウンターがリセットされ、カウントダウンが再び開始され、以前に送信された結果、たとえば「a」は破棄されます。 したがって、debounceステートメントは、指定されたタイムアウト中に新しいイベントをトリガーせずに継続した要素のみをチェーンに渡します。

デバウンスのサンプル画像



フィルター



この演算子は、不要なネットワーク呼び出しを回避するために、たとえば空の行などの不要な行を除外するために使用されます。



DistinctUntilChanged



この演算子は、ネットワーク呼び出しの重複を避けるために使用されます。 たとえば、最後の検索クエリが「abc」であった場合、ユーザーは「c」を削除して「c」を再入力しました。 結果は再びabcです。 ネットワーク呼び出しが同じパラメーターを使用して既にプロセス内にある場合、distinctUntilChangedステートメントは同じ呼び出しを再度行うことを許可しません。 したがって、distinctUntilChanged演算子は、 後で渡される繰り返し要素を削除します。

distinctUntilChangedサンプル画像



スイッチマップ



この例では、この演算子を使用して、ユーザーに結果を表示する必要がなくなったネットワーク呼び出しを除外します。 たとえば、最後の検索クエリは「ab」であり、このリクエストに対して有効なネットワークコールがありますが、ユーザーはこの時点で「abc」を入力します。 「ab」の結果は不要になり、「abc」の結果のみが必要になります。 救助のためのSwitchMap。 さらに、最後のクエリの結果のみを渡し、残りは無視します。



JavadocはswitchMap



を次のように説明します。



新しいObservable



返し、受け取った各Observable



要素に渡された関数を適用しますが、最後に受け取ったObservable



によってのみ作成された要素をさらに渡します。




やった! RxJavaなしで検索を実装することがどれほど難しいか想像してみてください。



完全な例を検討する場合は、次のプロジェクトをご覧ください



All Articles