お久しぶりです。もみじんです。
最近お仕事で Kotlin Android を使うことがあります。
3年前に触った時以来なので実装方法を思い出しつつ、今どきな方法を勉強しています。
どうやら今どきの方法(2023/02/12 現在)は、MVVMな感じで作る(Android公式では名言していないという話がありましたが、実質MVVMな感じと理解)のが主流ということがわかりました。
その要として、Data Binding を使用するということもわかりました。
ということで、この記事では、素人が listView を Data Binding を使って実装してみたという記事になります。
実装してみた
作ったもの
素人なので、シンプルなものを作ってみました。
アイテムの追加ボタンを押すとListViewにアイテムが増え、アイテムの削除ボタンを押すとListViewのアイテムが消えるというものです。
動いている動画は以下に置きました。
サンプルプログラム
サンプルプログラムは、Githubに上げました。
コード解説
前提
今回は、fragment の上に ListView を乗っけて、そのListViewにアイテムを追加していく実装にしました。
Data Bindig 設定
build.gradle に Data binding を使えるように宣言する。
android { ~~~ buildFeatures { dataBinding true } }
ViewModelの定義
MainViewModel.kt
Viewとロジックを仲立ちするファイルを作ります。
ファイル名は、MainViewModel.kt にしました。
今回は、ListViewの中身はListで保持しようと思います。
そして、Listには Book というモデルがリスト化されています。(Bookについては後述します。)
private val _bookItems = MutableLiveData<List>(listOf()) val bookItems: LiveData<List> get() = _bookItems
また、Listの中身を追加したり削除したり、ボタンを押したくなるので、それらができる関数も追加しました。
fun seletexBook() -> タップされたBookを Toast表示 fun addBook() -> Book の追加 fun removeBook() -> Book の削除
レイアウトを Data Bindig 仕様にする
fragment_main.xml
data タグを追加し、その中に variable タグも追加する。
(variable が view と ロジックを仲立ちものという個人的な認識。)
レイアウトは適当にいい感じに書いています。
カスタム ListView の実装
カスタム ListView で実装することが多いことを見越して、実装していきます。
book_item.xml
レイアウトは、単純な textView 一個だけにしました。
ここにも Data Bindig があります。
Book のデータクラスから title を android:text に渡しています。
Book.kt
ListViewに表示させる Book データクラスが定義しています。
簡素な作りです。
BookListBindingAdapter.kt
ListView の Adapter です。
カスタムListViewではおなじみのやつです。
Data Bindig では getView() の関数が特殊になります。
(book_item.xml と紐付けるをしている認識。)
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { val binding: BookItemBinding if(convertView == null){ binding = BookItemBinding.inflate(inflater, parent, false) binding.root.tag = binding } else { binding = convertView.tag as BookItemBinding } binding.book = getItem(position) as Book return binding.root }
ViewModelとロジックを紐付ける
MainFragment.kt
下準備ができたので、ViewModelとロジックを紐付けます。
onCreateView() で fragment_main.xml と紐付けています。
また、fragment_main.xml 内にある ListView に対してBookListBindingAdapter を紐付けています。
binding = FragmentMainBinding.inflate(inflater, container, false) binding.vm = viewModel binding.lifecycleOwner = this // listviewのadapterと紐付ける if (viewModel.bookItems.value != null){ binding.bookListView.adapter = BookListBindingAdapter(inflater.context, viewModel.bookItems.value!! ) }
onViewCreated() では ListViewのアイテム監視と、レイアウトにあるボタンのイベント受け取りを実装しています。
ListViewのアイテム監視は以下の箇所でしています。
アイテムが増えたり減ったりすると、この関数のイベントが発火します。
中身は、listview の中身の再定義です。
// bookList の値を監視する viewModel.bookItems.observe(viewLifecycleOwner) { bookList -> binding.bookListView.adapter = BookListBindingAdapter(view.context, bookList) }
他の箇所は、ボタンイベントになります。
ボタンが押されると ViewModelに定義してある関数が呼ばれます。
// listviewのアイテムクリック binding.bookListView.setOnItemClickListener { adapter, view, position, _ -> val book = adapter.getItemAtPosition(position) as Book viewModel.selectedBook(view.context, book) } // itemの追加ボタン binding.bookAddButton.setOnClickListener { viewModel.addBook() } // itemの削除ボタン binding.bookRemoveButton.setOnClickListener { viewModel.removeBook() }
まとめ
Kotlinで listView を Data Binding で実装してみました。
はじめは理解するのに時間がかかりましたが、なれるとすごく楽だなと感じます。
以前は、Viewとロジックがごっちゃになってかなり見づらいコードになってしまいましたが、このおかげでかなり見やすくなったと思います。
仕事でもバンバン使っていきたいと思います。
コメント