Google I/O 2018 Android Jetpack: what’s new in Android Support Library
のセッションであがってきたRecyclerViewの新しい機能、ListAdapterとRecyclerViewについて紹介します。
#ListAdapterとは
ListAdapterはSupport Library 27.1.0で提供されたAPIです。ListAdapterはGoogle I/O 2018のAndroid Jetpack: what’s new in Android Support Library
のセッションとAndroid Jetpack: manage infinite lists with RecyclerView and Paging
のセッションで次のような特徴が紹介されました。
・不変(Immutable)リストの動作
・Diffutilの利用によってコードが簡略される
・アニメーションを提供
ListApdaterは内部的にリストを読むだけの不変オブジェクトとして扱います。従って渡されたリストで直接的な要素の変更を許さず、もし変更するとしてもアップデートは反映されません。リストで要素が修正、追加、削除、移動が発生した場合、必ず変更が反映された新しいリストをListAdpaterへ渡します。バックグラウンドスレッドでリストが変更される場合、内部的にnotifyItem()関数が呼び出され、利用者はアップデートされたRecyclerViewを確認できます。これは既存のRecyclerViewアダプタとの違いであり、ListAdapterの特徴です。
こういう構造でLiveData又はObservableを利用し、リストの変更されたデータを読み、変更されたリストをListAdapterで実装することができます。
ListAdapterの状態を変更するためのAPIは新しいリストを設定する submitList(val lsit: List<T>)
の関数しかありません。内部動作に比べて外部のインターフェースは極端に単純です。
DiffUtil.ItemCallbackの実装
ListAdapterは2つのリストを比較するためのコンストラクタのパラメータで、 Diffuil.Itemcallback
が必要です。
Diffuil.Itemcallback
の実装は以下のようになります。
private val diffCallback = object : DiffUtil.ItemCallback<Int>() {
override fun areItemsTheSame(oldItem: Int, newItem: Int) =
oldItem == newItem // check uniqueness
override fun areContentsTheSame(oldItem: Int, newItem: Int) =
oldItem == newItem // check contents
}
実装すべきメソッドは以下の2つになります。
areItemsTheSame
2つのアイテム自体が同じものであるかを判定します。
areContentsTheSame
2つのアイテムのデータ内容が同じであるかを判定します。
ListAdapterの実装
ListAdapterの実装ですが、DiffUtil.ItemCallbackインスタンスを渡せばOKです。
private val adapter: ListAdapter<Int, MyViewHolder> = object : ListAdapter<Int, MyViewHolder>(diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
MyViewHolder(parent)
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bindTo(getItem(position))
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.adapter = adapter.apply {
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
recyclerView.scrollToPosition(0)
}
})
}
numbers.apply {
value = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
observe(this@MainActivity, Observer<List<Int>> {
adapter.submitList(it)
})
}
}
#まとめ
ListAdapterを使用すると、より簡単なコードでRecyclerViewを利用することができます。