
最近お仕事で 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とロジックがごっちゃになってかなり見づらいコードになってしまいましたが、このおかげでかなり見やすくなったと思います。
仕事でもバンバン使っていきたいと思います。