【Kotlin/Android Studio】ViewBindingの実装方法!違いと使い方

【Kotlin/Android Studio】ViewBindingの実装方法!違いと使い方

この記事からわかること

  • Android StudioViewBinding(ビューバインディング)を利用する方法
  • findViewById使用せずViewを取得する
  • ActivityFragmentでの実装手順
  • メモリリークを起こさないように扱う方法
  • DataBindingとの違い

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

ViewBindingとは?

公式リファレンス:ViewBinding

ViewBindingXMLレイアウトファイルと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クラス内にlateinitbindingプロパティを追加します。


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
    }
}

lifecycleOwnerviewLifecycleOwnerを指定している実装と指定していない実装を見かけますが、lifecycleOwnerviewLifecycleOwnerを指定するのはLiveDataを使用している場合にライフサイクルを指定しないとLiveDataが動作しなくなってしまうからです。

そのためLiveDataを使用しないならlifecycleOwnerの指定は不要でメモリリークもしないのかもしれませんが、公式の実装ではFragmentではlateinitを使用していないのでどちらにせよlateinitを使わない方が安全だと思います。

参考記事:1. DataBinding/ViewBindingでメモリリーク

ViewBindingとの違い

公式リファレンス:データ バインディングとの比較

DataBindingとの違いというより両者の違いをまとめると以下の通りです。

DataBindingは「ViewBinding + レイアウトとデータモデルの紐付け機能」が組み込まれたフレームワークになります。DataBindingと比べるとViewBindingは以下の特徴があります。

そのためDataBindingでレイアウトファイルとデータモデルを紐づける必要がない場合はパフォーマンスに悪影響が可能性があるのでViewBindingを使用してください。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index