RecyclerView는 데이터가 변하면 RecyclerView Adapter가 제공하는 notifyItem메서드를 사용해서 ViewHolder의 내용을 갱신할수있다.
그런데 이건 변경할때마다 갱신시켜줘야해서 번거롭다. 이때 사용할수 있는게 DiffUtil이다.
DiffUtil은 두 데이터셋을 받아서 그 차이를 계산해주는 클래스이다.
사용하기위해서는 DiffUtil.Callback()을 상속받아서 areItemsTheSame으로 비교대상 두 객체가 동일한지 확인하고, areContentsTheAsame으로 두 아이템이 동일한 데이터를 갖는지 확인해준다.
class VideoAdapter(
private val onClickItem: (Int, MyVideo) -> Unit,
) : ListAdapter<MyVideo, VideoAdapter.VideoViewHolder>(
object : DiffUtil.ItemCallback<MyVideo>(){
override fun areItemsTheSame(
oldItem: MyVideo,
newItem: MyVideo
): Boolean = if(oldItem is MyVideo.MyVideoItems && newItem is MyVideo.MyVideoItems){
oldItem.videoUri == newItem.videoUri
} else{
oldItem == newItem
}
override fun areContentsTheSame(
oldItem: MyVideo,
newItem: MyVideo
): Boolean = oldItem == newItem
}
){
abstract class VideoViewHolder(view: View) : RecyclerView.ViewHolder(view) {
abstract fun onBind(item: MyVideo)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoViewHolder =
VideoItemViewHolder(
VideoItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
onClickItem
)
override fun onBindViewHolder(holder: VideoViewHolder, position: Int) {
holder.onBind(getItem(position))
}
class VideoItemViewHolder(
private val binding: VideoItemBinding,
private val onClickItem: (Int, MyVideo) -> Unit
) : VideoViewHolder(binding.root){
override fun onBind(item: MyVideo) = with(binding){
if(item !is MyVideo.MyVideoItems) {
return@with
}
videoTitle.text = item.title
Glide.with(binding.root).load(item.thumbnail).into(binding.videoImage)
}
}
}
여기서 MyVideo는 데이터 객체를 담은 sealed interface이다.
sealed interface MyVideo : Parcelable{
@Parcelize
data class MyVideoItems(
val videoUri: String?,
var title: String?,
var thumbnail: String?,
var content: String?,
var isLike: Boolean? = false,
var views: Int?,
var tags: List<String>?,
val channelTitle: String?,
val publishedAt: String?,
) : MyVideo
}
이렇게 사용해주면 recyclerView에서 Notify를 귀찮게 하던걸 하지 않아도 된다!
listAdapter
listadapter
ListAdapter
Listadapter
리스트어뎁터