Android DataBindingで連打防止カスタムセッターを作る

開発部 大林
開発部 大林です!新米Androidエンジニアです。自作キーボードにハマっています。JapanTaxi AdventCalendarの14日目を担当することになりました。

最近、広告タブレットに 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のアクションに対しても連打をできないようにできました。
カスタムセッターを用意することで汎用的に使うことができ、大分コードがスッキリします。

JapanTaxiに興味を持ったら、まずはお話しませんか?