最近、広告タブレットに kotlin + MVVM + LiveData を導入しました。レイアウトxmlでButtonに紐づけたアクションが連打で誤動作してしまうため、連打防止用のカスタムセッターを作った話をします。
DataBindingカスタムセッターとは
@BindingAdapter("android:paddingLeft") public static void setPaddingLeft(View view, int padding) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); }
@BindingAdapterアノテーションを付与したメソッドを定義することでレイアウトxmlからメソッドを呼び出すことができるものです。既存の名前を付けることでオーバーライドされ、任意の名前を作ることで新しくメソッドを作成することができます。
連打防止拡張ClickLinsterを作る
kotlin拡張関数とRxBindingで拡張ClickListenerを作る
kotlin拡張関数とRxBindingを使って拡張ClickListenerを作ります。RxBindingはViewイベントをRxJavaで扱えるようにするライブラリです。 RxのThrottleFirstを使い、一度処理を受け付けたら一定時間は処理を無視するようにすることで連打を防止します。
fun View.setOnProtectBarrageClickListener(listener: View.OnClickListener){ clicks().throttleFirst(2000L, TimeUnit.MILLISECONDS) .subscribe { listener.onClick(this) } }
DataBindingカスタムセッターと紐付ける
拡張ClickListenerを作成したので、これをDataBindingカスタムセッターと紐付けることでButtonに設定されたメソッドが連打で実行されないようにします。※BindingAdapterはpublicなクラス関数でないといけないのですが、kotlinで何故か実現できなかったためjavaになっています。(今後の課題ですね)
@BindingAdapter("app:onClick") public static void setClick(View view, View.OnClickListener listener){ ViewExtensionKt.setOnProtectBarrageClickListener(view, listener); }
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" app:onClick="@{() -> viewmodel.Hoge(...)}" />
今回は app:onClick に紐づけたのでこれで連打されてもviewmodel.Hoge() メソッドが連続して実行されることはありません。
おわりに
これでDataBindingで指定したButtonのアクションに対しても連打をできないようにできました。カスタムセッターを用意することで汎用的に使うことができ、大分コードがスッキリします。