DataBindingLibrary でソースコードから findViewById を一掃する - proudust.github.io

DataBindingLibrary でソースコードから findViewById を一掃する

概要

Android Jetpack のコンポーネントの一つ、Data Binding Library を活用し、ソースコード内から findViewById による View の取得を一掃した備忘録。

1. Data Binding Library を有効化する

app/build.gradledataBinding.enabled = true を追加する。

android {
    // 中略
    dataBinding {
        enabled = true
    }
}

以上を追記

2. レイアウトを <layout></layout> で囲う

layout/*.xml の頭と尻に <layout></layout> を書き加え、xmlns:* だけ <layout> に移動する。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- レイアウト設定 -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".HogeActivity">

        <!-- 中略 -->

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

すると layout/*.xml を元に ViewDataBinding を継承した *Binding クラスが自動生成される。
クラスの名前は xml の名前を UpperCamelCase に変換したものが使われる。
自動生成されない場合は一回ビルドし直すと出るかも。

4. Binding クラスを使用する

指定する対象によって方法が若干異なる。

Activity の場合

Activity.java を下記のように編集する。

 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
-    setContentView(R.layout.activity);
+    final ActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.activity);

-    final TextView textView = findViewById(R.is.text_view);
-    textView.setText("HogeFuga");
+    binding.textView.setText("HogeFuga");

DataBindingUtil.setContentView の戻り値の型に注意。(総称型のため、ViewDataBinding を継承しているクラスなら何でも受け取れてしまう)

Fragment の場合 (パターン1)

Fragment.java を下記のように編集する。
Binding クラスから View を生成するパターン。フィールドに Binding クラスを持つ必要があるのがイマイチか。

+private FragmentBinding binding;

 @Override
 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                          @Nullable Bundle savedInstanceState) {
-    return inflater.inflate(R.layout.fragment, container, false);
+    binding = FragmentBinding.inflate(inflater, container, false);
+    return binding.getRoot();
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
     super.onActivityCreated(savedInstanceState);
-    final TextView textView = findViewById(R.is.text_view);
-    textView.setText("HogeFuga");
+    binding.textView.setText("HogeFuga");
 }

Fragment の場合 (パターン2)

Fragment.java を下記のように編集する。
View を先に生成し、それを元に Binding インスタンスを生成するパターン。この場合はフィールドに持つ必要はない。

+private FragmentBinding binding;

 @Override
 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                          @Nullable Bundle savedInstanceState) {
     return inflater.inflate(R.layout.fragment, container, false);
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
     super.onActivityCreated(savedInstanceState);
-    final TextView textView = findViewById(R.is.text_view);
-    textView.setText("HogeFuga");
+    final FragmentBinding binding = FragmentBinding.bind(getView());
+    binding.textView.setText("HogeFuga");
 }

RecyclerView.Adapter の場合

RecyclerView.Adapter に使うなら、groupieepoxy使ったほうが RecyclerView.ViewHolder が不要になって良いと思う。

 @NonNull
 @Override
 public MainViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-    final View view = inflater.inflate(R.layout.recycler_row, parent, false);
-    return new ViewHolder(view);
+    final RecyclerViewAdapterBinding binding = RecyclerViewAdapterBinding.inflate(inflater, parent, false);
+    return new ViewHolder(binding);
 }

 @Override
 public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
     holder.bind("HogeFuga");
 }

 class ViewHolder extends RecyclerView.ViewHolder {
     @NonNull
-    private final TextView textView;
+    private final RecyclerRowBinding binding;

-    private MainViewHolder(@NonNull View view) {
-        super(view);
-        textView = view.findViewById(R.id.text_view);
+    private MainViewHolder(@NonNull RecyclerRowBinding binding) {
+        super(binding.getRoot());
+        this.binding = binding;
     }

     void bind(@NonNull String text) {
-        textView.setText(text);
+        binding.textView.setText(text);
     }
 }

気になる点

  • Fragment に使う場合はパターン 1、2 のどちらが適切なのか

Proudust

Proudust

Virtual cockadoodledoo