데이터를 받아오고 이를 레이아웃에 직접 연결하는 함수를 실행시키는 클래스
= ListView나 App의 특정 데이터와 RecyclerView의 view를 Bind하는 것을 도와준다.
- 미리 생성해둔 뷰홀더 객체에 사용자가 원하는 데이터 리스트를 주입하고 데이터 리스트에 변경사항이 있을 때 이를 UI에 반영한다.
하지만 기존에 notifyDataSetChanged()
를 사용하면 리스트 내의 데이터가 바뀌면 리스트 전체가 바뀌었음 -> 지연 시간 발생(Flickering Issue)
이런 현상을 막고자 DiffUtil
이 나왔다.
두 목록 간의 차이를 계산하고 첫 번째 목록을 두 번째 목록으로 변환하는 업데이트 작업 목록을 출력하는 유틸리티 클래스
유형
abstract class DiffUtil.CallBack
: 두 목록 간의 차이를 계산하는 동안 DiffUtil에서 사용하는 콜백 클래스class DiffUtil.DiffResult
: 호출 결과에 대한 정보 유지하는 클래스abstract class DiffUtil.ItemCallback<T>
: 목록에서 null이 아닌 두 항목 간의 차이를 계산하기 위한 콜백
//diffutil -> 새로운 아이템 할당할지 말지 판단해주는 ->콜백 구현해야함
companion object{
val diffUtil=object:DiffUtil.ItemCallback<Book>(){
// 두 아이템이 동일한 아이템인지 체크. 보통 고유한 id를 기준으로 비교
override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean {
return oldItem.id==newItem.id
}
// 두 아이템이 동일한 내용을 가지고 있는지 체크. areItemsTheSame()이 true일때 호출됨
override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean {
return oldItem==newItem
}
}
abstract class ListAdapter<T, VH: RecyclerView.ViewHolder?> : RecyclerView.Adapter
RecyclerView.Adapter 백그라운드 Thread에서 목록 간의 차이 계산을 포함하여 목록 데이터에 표시하기 위한 기본 클래스.
항목 액세스 및 계산을 위한 어댑터 공통 기본 동작을 구현하는 편리한 래퍼.
- ListAdapter<데이터클래스, 리사이클러뷰 뷰홀더>를 인자로 받음. 어댑터 내에서 리스트를 정의하는 것이 아니라 리스트 자체에서 데이터 리스트를 정의하기 때문
- 그래서 일반적인 RecyclerViewAdapter와 다르게 getItemCount() 구현 안 해도 됨
FarmRVAdapter.kt
class FarmRVAdapter: ListAdapter<RVFarmDataModel, FarmRVAdapter.ViewHolder>(diffUtil) {
inner class ViewHolder(private val binding: RvLocalFarmBinding): RecyclerView.ViewHolder(binding.root){
fun bind(item : RVFarmDataModel){
binding.rvFarmImage.setImageResource(item.farm_image)
binding.rvFarmName.text = item.farm_name
binding.rvFarmSize.text = item.farm_size
binding.rvFarmPrice.text = item.farm_price
binding.bookMark.setOnClickListener {
binding.bookMark.isSelected = !binding.bookMark.isSelected
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FarmRVAdapter.ViewHolder {
return ViewHolder(RvLocalFarmBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: FarmRVAdapter.ViewHolder, position: Int) {
holder.bind(currentList[position])
}
companion object{
val diffUtil = object: DiffUtil.ItemCallback<RVFarmDataModel>(){
override fun areItemsTheSame(
oldItem: RVFarmDataModel,
newItem: RVFarmDataModel
): Boolean {
TODO("Not yet implemented")
}
override fun areContentsTheSame(
oldItem: RVFarmDataModel,
newItem: RVFarmDataModel
): Boolean {
TODO("Not yet implemented")
}
}
}
}
Fragment에서 연결
class HomeFragment : Fragment() {
private lateinit var homeBinding : FragmentHomeBinding
private lateinit var adapter: FarmRVAdapter
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
adapter = FarmRVAdapter()
// 우리 동네 농장 아이템
val local_farm_items = mutableListOf<RVFarmDataModel>()
homeBinding.rvHomeFarm.adapter = adapter
adapter.submitList(local_farm_items)
homeBinding.rvHomeFarm.layoutManager = GridLayoutManager(requireActivity(), 2)
local_farm_items.add(RVFarmDataModel(R.drawable.farm_image_example,"고덕 주말 농장","3평","150,000"))
local_farm_items.add(RVFarmDataModel(R.drawable.farm_image_example,"고덕 주말 농장","3평","150,000"))
local_farm_items.add(RVFarmDataModel(R.drawable.farm_image_example,"고덕 주말 농장","3평","150,000"))
local_farm_items.add(RVFarmDataModel(R.drawable.farm_image_example,"고덕 주말 농장","3평","150,000"))
return view.root
}