visible true

技術的なメモを書く

Data Binding Libraryが吐くコードがLintに怒られる時がある

問題

booleanを使ってandroid:backgroundの値を制御するようなレイアウトを書いたとします。

<data>
  <variable name="focused" type="boolean" />
</data>
<FrameLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="@{focused? @drawable/shape_focused : null}"
                >

この時Data Binding Libraryが以下のようなコードを吐きます。

this.mboundView1.setBackground((android.graphics.drawable.Drawable) FocusedAndroidDrawableShapeFocusedObjectnull);

アプリのminSdkVersionが16未満の場合Lintに以下の様に怒られてしまいます。

NewApi: Calling new methods on older versions

View#setBackground(Drawable)API Levelが16だからですね。@TargetApi等で分岐しろと言われます。

対応

さて、Bindingクラスは自動で生成されるので@TargetApiを追加できません。こういう時はBindingAdapterアノテーションを使います。BindingAdapterアノテーションは属性値のバインド処理を定義できるアノテーションです。どこか適当な場所(アプリケーションID.databindingなどが望ましいかもしれません)にViewGroupAdapterというクラスを作ります。

public class ViewGroupAdapter {
  @BindingAdapter("android:background")
  public static void setBackgroundAdapter(ViewGroup viewGroup, Drawable drawable) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
      setBackground(viewGroup, drawable);
    } else {
      setBackgroundDrawable(viewGroup, drawable);
    }
  }

  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  public static void setBackground(ViewGroup viewGroup, Drawable drawable) {
    viewGroup.setBackground(drawable);
  }

  public static void setBackgroundDrawable(ViewGroup viewGroup, Drawable drawable) {
    viewGroup.setBackgroundDrawable(drawable);
  }
}

ViewGroupAdapterは"android:background"を処理するメソッドを定義しています。対象をViewGroupにしているのでFrameLayoutにも適用されます。ImageViewなどViewGroupと継承関係のないViewへは適用されないのでご注意ください。

このクラスを定義して再度コンパイルすると生成されるコードが以下のように変化します。これでLintに怒られずにすみますね。

アプリケーションID.databinding.ViewGroupAdapter.setBackgroundAdapter(this.mboundView1, (android.graphics.drawable.Drawable) FocusedAndroidDrawableShapeFocusedObjectnull);

最後に

BindingAdapterアノテーションはアプリケーション全体に適用されるので適当にやりすぎると確実に事故ります。用法用量を守って活用しましょう。

ところでC88でTechBooster本に参加しています。Data Binding Libraryについて根掘り葉掘り書いたのでよかったら買ってください。

techbooster.github.io