ListAdapter
기존에 안드로이드 앱 개발을 하면서 RecyclerView의 Adapter를 만들 때 항상 RecyclerView Adapter
를 사용했습니다.
하지만 아시다시피 RecyclerView Adapter는 데이터가 변경될 때마다 notifyDataSetChanged()
을 호출해서 변경되었다는 것을 알려주어야 했습니다.
이제껏 이런 방법만 있는 줄 알았는데, 안드로이드에 대해서 더 공부를 하다보니 ListAdapter
라는 것이 있었습니다.
ListAdapter
는 Jetpack 라이브러리 중 하나로 RecyclerView Adapter의 형태 중 하나로, 데이터가 변경될 때 효율적으로 화면을 갱신할 수 있습니다.
데이터 변경 시에만 필요한 항목을 업데이트할 수 있기 때문에 성능을 최적화할 수 있습니다.
ListAdapter<MyData, MyViewHolder>(MyDataDiffCallback())
DiffUtil.ItemCallback
을 구현해서 이전 데이터와 새로운 데이터의 차이를 계산합니다.
override fun areItemsTheSame(oldItem: MyData, newItem: MyData): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: MyData, newItem: MyData): Boolean {
return oldItem == newItem
}
Adapter에서 submitList(val list: List<T>)
를 통해서 새로운 데이터를 업데이트하게 됩니다.
간단한 예제 코드로 구현해 보았습니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/main_text1"
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="ListAdapter 예제"
android:gravity="center"
android:textSize="30dp"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_rv"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/main_text1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/main_text1"
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="ListAdapter 예제"
android:gravity="center"
android:textSize="30dp"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_rv"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/main_text1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
class ExamDiffUtilCallBack : DiffUtil.ItemCallback<String>() {
override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem == newItem
}
}
class ExamViewHolder(
private val binding: ItemMainBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(str: String) {
binding.itemText.text = str
}
companion object {
fun valueOf(parent: ViewGroup): ExamViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemMainBinding.inflate(
layoutInflater,
parent,
false
)
return ExamViewHolder(binding)
}
}
}
class ExamAdapter : ListAdapter<String, ExamViewHolder>(ExamDiffUtilCallBack()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExamViewHolder {
return ExamViewHolder.valueOf(parent)
}
override fun onBindViewHolder(holder: ExamViewHolder, position: Int) {
holder.bind(getItem(position))
}
override fun submitList(list: MutableList<String>?) {
super.submitList(list)
}
}
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val fakeDataList = mutableListOf<String>()
fakeDataList.add("Item 1")
fakeDataList.add("Item 2")
fakeDataList.add("Item 3")
fakeDataList.add("Item 4")
fakeDataList.add("Item 5")
val adapter = ExamAdapter()
adapter.submitList(fakeDataList)
with(binding){
mainRv.adapter = adapter
mainRv.layoutManager = LinearLayoutManager(this@MainActivity)
}
}
}
LayoutManager
의 경우 굳이 Activity에서 지정해주지 않아도 됩니다. <androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_rv"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/main_text1"/>