RxJavaを使用してEditText#onTextChangedコールバックを最適化する

ここに写真の説明を挿入

onTextChanged


EditTextは一般的に使用されるテキスト入力コントロールですが、そのコールバックインターフェイスは使いやすいように設計されていません。3つのインターフェイスを実装する必要があります。私はほとんどのシナリオのみを気にします。onTextChanged

editText.addTextChangedListener(object : TextWatcher {
    
    
    override fun afterTextChanged(s: Editable?) {
    
    
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    
    
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    
    
        Log.d(TAG, "query: ${
      
      s}")
    }
})

そして、最も懸念されるのonTextChangedは、そのセマンティクスが単純すぎるため(変更するたびにコールバックする)、一般的な实时搜索シナリオなど、一部のビジネスシナリオでは期待される結果を達成できない場合、入力ボックスにキーワードを入力してリアルタイムで実行できることを望んでいます。この時点でLenovoまたはSearchを使用EditText#onTextChangedすると、多くの問題が発生します。

複数のコールバック

たとえば、上記のコードでは、1つずつ入力a b c d eして、次のログを取得します

query: a
query: ab
query: ab
query: abc
query: abcd
query: abcd

その中で、abとabcdは2回出現します。調査の結果、EditText
androidの設定に関連しています-TextWatcherイベントが複数回
発生しています-スタックオーバーフロー。もちろん、この問題はリアルタイム検索シーンでは発生しません。また、このコントロールがどのようにピットインしているかを反映しています。

頻繁にトリガーされる

入力フィードバック实时効果があることが望ましいが、鋭すぎないようにしたい(高いメンテナンス|||人間の真)、たとえば、「A」「AA」「AAA」「AAAA」,说明我们的目的性很强,只对最后的「AAAA」などの高速入力の組み合わせの場合結果を得るだけ

非同期の結果が正しくない

非同期呼び出しは入力後に“a” “aa”開始されるため、複数の連続する非同期要求の結果のコールバックタイミングが期待を満たさない可能性があります。たとえば、入力は2つの非同期要求をトリガーしますが、「a」の結果が返され、入力ボックスがすでに「aa」状態のまま。


RxJava最適化を使用する


上記の問題はすべてEditText#onTextChanged、予想されるビジネスシナリオを満たせないコールバックセマンティクスが原因で発生します。現時点では、RxJavaを使用してそれらを最適化できます。

複数回のコールバック

val queryPublisher = PublishSubject.create<String>()

editText.addTextChangedListener(object : TextWatcher {
    
    
    override fun afterTextChanged(s: Editable?) {
    
    
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    
    
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    
    
        queryPublisher.onNext(s.toString())
    }
})

queryPublisher.distinctUntilChanged().subscribe({
    
    
    Log.d(TAG, "query: ${
      
      it}")
})

PublishSubjectストリームパイプラインを提供しonTextChangedます。受信した元のコールバック
distinctUntilChanged使用して、各値が1回だけコールバックされるようにします。

query: a
query: ab
query: abc
query: abcd

頻繁なトリガー

queryPublisher.distinctUntilChanged()
        .debounce(500, TimeUnit.MILLISECONDS)
        .subscribe({
    
    
            Log.d(TAG, "query: ${
      
      it}")
        })

debounce防振追加するため使用します。これthrottleLastも同様の関数演算子ですが、効果はこの要件の期待を満たしていないことに注意してください。2つの違いを比較してみましょう。

  • デバウンス
    が一定期間データを送信した、新しいデータがない場合は実際にデータが送信されます。この期間中に新しいデータが送信された場合は、このデータが送信されるデータ項目として使用され、タイミングが再開されます。
    ここに写真の説明を挿入

  • スロットル
    ラストは、各期間の最後のデータを送信します。ユーザーは、継続的な入力の途中で結果を要求する場合がありますが、これは期待に応えません。
    ここに写真の説明を挿入

非同期の結果が正しくない

2つの解決策があります。

処分する

private var searchDisposable: Disposable? = null

override fun onCreate(savedInstanceState: Bundle?) {
    
    
	// 略...

    queryPublisher.distinctUntilChanged()
            .debounce(500, TimeUnit.MILLISECONDS)
            .subscribe({
    
    
                Log.d(TAG, "query: ${
      
      it}")
                searchDisposable?.dispose()
                searchDisposable = search(query = it)
                        .subscribe({
    
    
                            // 搜索结果显示
                        })
            })
}

/**
 * 结果请求
 */
fun search(query: String?): Observable<ArrayList<String>> {
    
    
    // 略...
    return Observable.empty<ArrayList<String>>()
}

新しい入力を取得したら、前の非同期リクエストを手動で停止します

switchMap

switchMapオペレーターはに比べてdisposeよりエレガントです

RxJavaはswitchMap演算子も実装しています。これはflatMapとほぼ同じように動作しますが、ソースObservableによって新しいアイテムが発行されるたびに、以前に発行されたアイテムから生成されたObservableのサブスクライブを解除してミラーリングを停止し、現在のアイテムのミラーリングのみを開始します。

switchMapそしてflatMap同様に、また、ストリームを切り替えるために使用することができますが、新しいswitchMapストリームへのスイッチは、古いストリームは自動的に停止したとき。flatMapとの比較を通じて、その意味を理解してください。

  • flatMap
    ここに写真の説明を挿入

  • switchMap
    ここに写真の説明を挿入

上記の例では、switchMapの変換後、コードは非常に断固としたものになります。

override fun onCreate(savedInstanceState: Bundle?) {
    
    
    // 略...

    queryPublisher.distinctUntilChanged()
            .debounce(500, TimeUnit.MILLISECONDS)
            .switchMap {
    
     search(it) }
            .subscribe({
    
    
                // 搜索结果显示
                Log.d(TAG, "result: ${
      
      it}")
            })
}

おすすめ

転載: blog.csdn.net/vitaviva/article/details/107879099