【Kotlin/Android Studio】ViewBindingの実装方法!違いと使い方
この記事からわかること
- Android StudioのViewBinding(ビューバインディング)を利用する方法
- findViewByIdを使用せずにViewを取得する
- ActivityとFragmentでの実装手順
- メモリリークを起こさないように扱う方法
- DataBindingとの違い
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Android Studio:Koala
- Kotlin:1.8.20
ViewBindingとは?
ViewBindingはXMLレイアウトファイルとKotlin側のコードを紐づけることができる機能でAndroid Jetpackの一部として組み込まれています。findViewById
を使用して取得していたViewの参照を簡単に取得できるようになるだけでなく、Viewのキャストエラーやnull安全性などバグのリスクとコードの見通しの改善が期待できます。
ViewBinding
を有効にするとXMLレイアウトファイルに紐づいたバインディングクラスが自動生成されます。生成されるバインディングクラス名はactivity_main.xml(MainActivity.kt)
ならActivityMainBinding
のようになります。
※fragment_input.xml(InputFragment)
ならFragmentInputBinding
導入方法
ViewBinding
を導入するには「build.gradle(Module)」内のandroid
の中にbuildFeatures { viewBinding true }
を追記して「Sync Now」をクリックします。特に依存関係を追加する必要はありません。
android {
// 〜〜〜〜〜〜
buildFeatures {
viewBinding true
}
// 〜〜〜〜〜〜
}
ViewBinding
ではこの実装だけで導入が完了し、ビルドしたタイミンングでレイアウトファイルに対応した各バインディングクラスが自動生成されます。
特定のレイアウトファイルを除く
バインディングクラスの生成を特定のレイアウトファイルを除きたい場合はレイアウトファイルにtools:viewBindingIgnore
属性を追加しtrue
を渡します。
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
Activityでの使い方
ViewBinding
を使用してActivityからレイアウト内のウィジェットを参照するためにはまずActivity
クラス内にlateinit
でbinding
プロパティを追加します。
private lateinit var binding: ActivityMainBinding
続いてonCreate
メソッド内で行っていたレイアウトとコードの紐付けを書き換えます。対象のバインディングクラスを使用してレイアウトをインフレートしてインスタンスを生成し、root
プロパティからレイアウトXMLファイルのルートビューを取得します。最後にsetContentView
でViewを紐付けすれば完了です。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
これでbinding
から対象レイアウトファイルのViewの参照を取得することができるようになりました。参照を取得できるのはレイアウトファイルでid
を指定したものです。例えばtransfer_button
というIDを指定していた場合は...
<Button
android:id="@+id/transfer_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Transfer"quot; />
transferButton
というプロパティからViewの参照を取得することができるようになります。
binding.transferButton.setOnClickListener {
supportFragmentManager.beginTransaction().apply {
add(R.id.main_frame, ThirdFragment())
addToBackStack(null)
commit()
}
}
Fragmentでの使い方
ViewBinding
を使用してFragmentからレイアウト内のウィジェットを参照する方法も基本的にはActivityと変わりありません。ただ1つ注意点があり、lateinit
ではなくprivate var
で参照用のbinding
と更新用の_binding
を用意し、onDestroyView
メソッドで明示的に解放するように実装することが公式より推奨されています。
公式リファレンス:フラグメントでビュー バインディングを使用する
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.doneButton.setOnClickListener {
parentFragmentManager.popBackStack()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
lateinitではメモリリークの危険
lateinit
で実装するとメモリリークの原因になるので注意してください。これはbinding.lifecycleOwner
に指定しているライフサイクルとviewLifecycleOwner
が微妙に異なるためです。
class FirstFragment : Fragment() {
private lateinit var binding: FragmentFirstBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentFirstBinding.inflate(inflater, container, false)
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}
}
lifecycleOwner
にviewLifecycleOwner
を指定している実装と指定していない実装を見かけますが、lifecycleOwner
にviewLifecycleOwner
を指定するのはLiveDataを使用している場合にライフサイクルを指定しないとLiveDataが動作しなくなってしまうからです。
そのためLiveData
を使用しないならlifecycleOwner
の指定は不要でメモリリークもしないのかもしれませんが、公式の実装ではFragmentではlateinit
を使用していないのでどちらにせよlateinit
を使わない方が安全だと思います。
参考記事:1. DataBinding/ViewBindingでメモリリーク
ViewBindingとの違い
DataBindingとの違いというより両者の違いをまとめると以下の通りです。
- ViewBinding:レイアウトとViewの参照の自動紐付け機能
- DataBinding:レイアウトとViewの参照の自動紐付け機能 + レイアウトとデータモデルの紐付け機能
DataBindingは「ViewBinding + レイアウトとデータモデルの紐付け機能」が組み込まれたフレームワークになります。DataBindingと比べるとViewBindingは以下の特徴があります。
- コンパイルが高速・・・アノテーション処理が不要のため
- 組み込みが用意・・・ XMLレイアウトへの追記が不要
そのためDataBindingでレイアウトファイルとデータモデルを紐づける必要がない場合はパフォーマンスに悪影響が可能性があるのでViewBinding
を使用してください。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。