言いたいことはそれだけか

KotlinとかAndroidとかが好きです。調べたことをメモします。٩( 'ω' )و

RxTextView#textChanges()でdistinctUntilChangedする時にeventが流れない時がある

みんな大好きRxBinding1 ですが、ちょっとハマることがあったのでメモ。

RxTextView#textChanges()EditText の入力イベントを監視する。その時に重複した入力をdistinctUntilChanged()で削ろうとしたら以降何もeventが流れない現象に遭遇した。

RxTextView.textChanges(editText)
        .distinctUntilChanged() //  ここでevnetが止められるから
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe {
            Log.d("SampleApp", it.toString()) // ここは実行されない
        }

textChanges()は内部ではTextWatcherを使っていて、これがTextの変更を検出するとCharSequenceを返してくれるのだが、こいつはmutableで毎度同じinstanceを返すのだ。同じinstanceなのでchangeしたと見なされずいつまでたっても次のeventが流れてこない。

なので、CharSequenceからStringを取り出してやれば想定していた挙動になる。

RxTextView.textChanges(editText)
        .map { it.toString() } //  ここでStringに変換すると
        .distinctUntilChanged() 
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe {
            Log.d("SampleApp", it.toString()) // ここが実行される
        }

そもそもなんで RxTextView#textChanges() で入力の重複を防ぎたかったかというと、機種依存でSoftware Keyboardのsearch buttonをtapした時にtextChangesのeventがemitされちゃう場合があって、これを防ぎたかったから。これはRxTextViewというよりは、内部で使われているTextWatcherでeventが発火しているからなんだけど、keyboardの機種依存周りつらすぎてなんか仕様とか作って統一して欲しい…


  1. AndroidでReactive Programmingする時に、Viewのイベントをstreamで扱えるのが最大の利点だと思ってしまいそうになるくらいに大好き