View BindingはViewシステムを用いている場合に、プログラムから子Viewの参照を容易にする仕組みです。
Googleは「利点がある」と述べています。しかし、私は利点に感じないので、積極的な利用をしていません。
今まで、単なるオプションと考えていたのですが、最近は一般的になりつつあり、世に出回っているサンプルで頻繁に見かけるようになりました。
ですので、ここに備忘録として、まとめます。
※環境:Android Studio Ladybug | 2024.2.1
Kotlin 1.9.24
(Viewシステムのプロジェクトは1.9.24が選ばれる)
(Composeのプロジェクトは2.0.0が選ばれる)
目次
View Bindingとは
View BindingはViewシステム(レイアウト.xmlで画面構成を定義する環境)を用いている場合に、プログラムからView(ButtonやtextViewなど)の参照を容易にする仕組みです。
例えば、以下のようなレイアウトファイル(activity_main.xml)があったとします。
...
<TextView
android:id="@+id/txtMesg"
.../>
...
View Bindingでは、レイアウトファイルからBindingクラス(ActivityMainBinding)を自動生成し、このクラスを使ってViewの参照を可能にします。
val _binding = ActivityMainBinding.inflate(layoutInflater)
val _txtMesg = _binding.txtMesg // TextViewの参照
val _txtMesg = findViewById<TextView>(R.id.txtMesg)
View Bindingの利点は次のように述べられています。※[ ]内は私的な感想
- [△]Viewの参照を簡単に書ける
- [?]null安全性:無効なIDのために例外の発生するリスクが無い
- [?]型安全性:無理に異なる型(View)へ変換するミスが無い
環境設定
View Bindingを利用するための環境設定です。
View Bindingの有効化
View Bindingはモジュール毎に有効・無効を指定します。
有効にするために、「app/build.gradle」へ次の設定を行います。
android {
...
buildFeatures {
viewBinding = true
}
...
}
Viewシステムのプロジェクト作成
View BindingはViewシステムを用いている場合の機能です。
現状はJetpack Composeによる開発が主流になっているので、Viewシステムを意図的に選択しなければなりません。
新規プロジェクトの作成時に、「Views Activity」を選んでください。

Bindingの動作
View Bindingの有効化が行われると、Android Studioはレイアウトファイルを認識する際に、Bindingクラス(例:ActivityMainBinding)を自動生成します。


Bindingクラスのクラス名は、レイアウトファイル名(例:activity_main.xml)を図のように変換したものになります。

Bindingクラス#infulate()を実行すれば、BindingクラスのプロパティにViewの参照が登録されるので、そのインスタンスから取得できるようになります。
プロパティ名はViewの「リソースID」になっています。ただし、トップViewは「root(固定の名前)」になっています。
binding: ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) // トップViewをコンテンツとして指定
val _txtMesg = binding.txtMesg // TextView

Activityの例
Activity#setContentViewは引数にViewを採れるので、ActivityMainBinding#rootを入力しています。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
android:id="@+id/main"
...>
<LinearLayout android:id="@+id/layMesgPanel" ...>
<TextView android:id="@+id/txtMesg" ... />
<LinearLayout android:id="@+id/layBtnPanel" ...>
<Button android:id="@+id/btnRed" ... />
<Button android:id="@+id/btnBlue" ... />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.sample1)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val _btnRed = binding.btnRed
val _btnBlue = binding.btnBlue
val _txtMesg = binding.txtMesg
_btnRed.setOnClickListener { _txtMesg.setTextColor(Color.RED) }
_btnBlue.setOnClickListener { _txtMesg.setTextColor(Color.BLUE) }
}
}
Fragmentの例
Fragment#onViewCreatedの引数viewはFragmentのトップViewが渡されてきます。
しかし、この引数viewは使用しません。
_bindingプロパティに保持したBindingインスタンスを用いて、Viewの参照を行います。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MesgPanelFragment">
<LinearLayout android:id="@+id/layMesgPanel" ...>
<TextView android:id="@+id/txtMesg" ... />
<LinearLayout android:id="@+id/layBtnPanel" ...>
<Button android:id="@+id/btnRed" ... />
<Button android:id="@+id/btnBlue" ... />
</LinearLayout>
</LinearLayout>
</FrameLayout>
class MesgPanelFragment : Fragment() {
private var _binding: FragmentMesgPanelBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentMesgPanelBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val _btnRed = binding.btnRed
val _btnBlue = binding.btnBlue
val _txtMesg = binding.txtMesg
_btnRed.setOnClickListener { _txtMesg.setTextColor(Color.RED) }
_btnBlue.setOnClickListener { _txtMesg.setTextColor(Color.BLUE) }
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Fragmentはdetach(デタッチ:利用が終わり、取り外す)されると、Viewは破棄されてメモリーから消えますが、Fragment自体はフラグメントマネージャーで管理が継続され、メモリーに残ります。
そのため、Bindingインスタンス内にViewの参照を保持していると、Viewが破棄できずに残ってしまいます。
Frangent#onDestoryViewで_bindingプロパティへnullを代入して、Bindingインスタンスを破棄することで、上記の問題を回避します。
RecyclerViewの例
ViewHolderクラスにおいて、引数をアイテムのトップViewからBindingへ変更すれば良いです。
このViewHolderとBindingはViewの参照を持つという点で、役割が重複しています。どちらかに集約したいですが、方法はありません。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_margin="1dp"
android:background="#DFE6F6">
<TextView android:id="@+id/txtMesg" ... />
</androidx.constraintlayout.widget.ConstraintLayout>
class ArrayAdapter(var items: Array<String>)
: RecyclerView.Adapter<ArrayAdapter.ArrayViewHolder>() {
// ----- ビューホルダー ------------------------------------------
class ArrayViewHolder(val binding: SimpleItemBinding)
: RecyclerView.ViewHolder(binding.root) {
val mesg = binding.txtMesg
}
// ----- アダプター本体 ------------------------------------------
override fun getItemCount(): Int {
return items.size // アイテム数を返す
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
: ArrayViewHolder {
val _binding = SimpleItemBinding.inflate(
LayoutInflater.from( parent.context),
parent,
false
)
return ArrayViewHolder(_binding) // ViewHolderを返す
}
override fun onBindViewHolder(holder: ArrayViewHolder, position: Int) {
holder.mesg.text = items[position] // 要素とデータを紐づける
}
}
※その他、RecyclerView関連の記述は「RecyclerViewの実装」を参照
関連記事:
