ListAdapter Android Dev

#目次

1. ListAdapterとは
2. サンプルコード
3. まとめ

## 実装内容

<img width="400" alt="Screenrecorder-2022-02-02-17-11-12-611.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512202/8d4cfc4f-ceb5-b3bb-a7fd-230ed422d267.gif">


##1. ListAdapterとは

``ListAdapter``‥**Recyclerview**を使用する際に，``ViewHolder``がどのように生成されるかを定義できるクラスで，コンストラクタの引数として**DIFF_UTIL**のオブジェクトを与えることできる．``ListAdapter``の``submitList(List)``を呼び出し，リストを渡しUIの要素として利用することができる．また，この時に渡したリストを， **DIFF_UTIL**が差分を求めることで，**notifydatasetchanged**等のメソッドを呼び出す必要がなくなる．個人的な解釈としては，``ViewHolder``の生成方法を定義するためのクラス，**DIFF_UTIL**を利用して，取得したリストの変化を検知するためのクラスとして解釈している．

##2. サンプルコード

実装する内容は，``ListAdapter``を継承した**PersonListAdapter**，継承先のコンストラクタに渡す，**DiffUtil**，Viewの内容を紐づける``ViewHolder``があります．

それでは，実際にサンプルコードから実装方法を確認します．(レイアウト，表示するリストの説明は省略します．)

``PersonListAdapter``

```kotlin
class PersonListAdapter: ListAdapter<Person, PersonViewHolder>(DIFF_UTIL) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PersonViewHolder {

        val layoutInflater = LayoutInflater.from(parent.context)

        //このviewの生成方法に注意する必要ある
        val binding = LayoutPersonDetailBinding.inflate(layoutInflater, parent, false)

        return PersonViewHolder(binding)
    }

    override fun onBindViewHolder(holder: PersonViewHolder, position: Int) {

        // 位置ごとで，viewと紐づける
        holder.bind(getItem(position))
    }

}
```

このクラスの役割は，Viewの情報を受け取って紐づけるViewHolderの生成方法と，表示するアイテムの位置とViweを紐づけるオーバーライドをここで行い，RecyclerViewの要素の作成方法を定義します．

``PersonViewHolder``

```kotlin
// layoutで紐づけられたviewを，ここでもらって，viewBindingで処理
class PersonViewHolder(
    private val binding: LayoutPersonDetailBinding
): RecyclerView.ViewHolder(binding.root) {

    fun bind(person: Person) {

        binding.nameTextview.text = person.name
        binding.ageTextview.text = person.age.toString()
    }
}
```

RecyclerView構成要素のlayoutのviewをここで受け取り，モデルと表示する要素が一致するように処理を行います．

``DiffUtil``

```kotlin
val DIFF_UTIL = object : DiffUtil.ItemCallback<Person>() {

    // オブジェクト特有の値を用いて比較を行う．
    override fun areItemsTheSame(
        oldItem: Person,
        newItem: Person
    ): Boolean {

        return oldItem.name == newItem.name
    }

    // オブジェクトの中身が同じであるかを確認する
    override fun areContentsTheSame(
        oldItem: Person,
        newItem: Person
    ): Boolean {

        // data class だから、この比較を行える
        return oldItem == newItem
    }
}
```

DiffUtilは，リストの差分を検知する役割を持っています．変更があった時に，リスト全体を呼び込んで変更を検知するわけではなく，変更があったポジションの変更を読み取ります．

``MainActivity``

```kotlin
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val listAdapter = PersonListAdapter()

        binding.recyclerview.adapter = listAdapter
        binding.recyclerview.layoutManager = LinearLayoutManager(applicationContext)
        listAdapter.submitList(Provider.personList)
    }
}
```

``submitList``で，表示したいリストを渡しています．上記の処理を完了すると，以下のようになります．

<img width="400" alt="Screenrecorder-2022-02-02-17-11-12-611.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512202/8d4cfc4f-ceb5-b3bb-a7fd-230ed422d267.gif">

##3. まとめ

RecyclerViewの実装に対して苦手意識があったのですが，ListAdapterを利用することで比較的楽に実装することができました．