Android
[Android Kotlin]: Multiple ViewHolder (멀티 뷰홀더)
KwakEuiJin
2023. 4. 20. 00:09
ViewHolder란?
- 공식문서 상 “ViewHolder는 RecyclerView 내에서의 위치에 대한 항목 보기 및 메타데이터를 설명한다” 라고 정의합니다.
- 즉 ViewHolder는 각 View의 요소들을 보관하는 holder 객체입니다.
- ListView나 RecyclerView에서 inflate를 최소화 하기 위해 View를 재사용 할 시 반복적인 findViewById의 호출 없이 재사용 할 수 있도록 ViewHolder를 사용하는 것을 ViewHolder패턴이라고 합니다.
- 이처럼 ViewHolder를 활용한다면 반복되는 View를 재활용하여 효율적으로 생성할 수 있으며 성능을 높이고 보일러플레이트 코드를 줄여나갈 수 있다는 장점이 존재합니다.
ListView에서의 ViewHolder
- ListView에서 ViewHolder는 Adapter내의 getView()함수에서 넘어오는 파라메터인 convertView를 활용하여 convertView가 null일때만 새로운 View를 inflate하여 메모리를 최소화 시키는 역할을 합니다.
- View를 inflate시 findViewById를 호출하게 되면 XML리소스에 접근하여 childrenView의 전체를 확인 후 가져오기 때문에 비용이 큽니다.
- 예시)
- //ListView Adapter inner class ViewHolder{ lateinit var textView:TextView; fun bind(name:String){ textView.text = name } } override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { val viewHolder:ViewHolder if (convertView == null){ val layoutInflater = LayoutInflater.from(parent.context) convertView = layoutInflater.inflate(R.layout.item_main,parent,false) viewHolder = ViewHolder() viewHolder.textView = convertView.findViewById(R.id.TextView) }else{ viewHolder = convertView.tag as ViewHolder } viewHolder.bind(list.name) return convertView }
- 하지만 ListView의 Adapter는 ViewHolder를 강제하지 않는 구조이며 단순히 View의 호출식을 줄이기 위한 저장소 역할이라는 한계를 가지고있습니다.
RecycleView에서의 ViewHolder
- RecyclerView는 ListView와 비슷한 기본 동작 구조인 List의 Size만큼 View를 inflate시킵니다. 다만 RecyclerView는 화면에 보이는 itemView에 대해서만 inflate시킨다는 점에서 차별점을 가지고 있습니다.
- 즉 RecyclerView에서의 ViewHolder는 itemView의 재사용(Recycler)과 유동적인 inflate를 위해 View와 Data를 담아주는 Holder클래스의 역할을 담당합니다.
- 또한 View를 inflate시키기 위해서는 메모리를 사용하게 됩니다. 이때 동적으로 주입되는 List를 활용하기 위해서 RecyclerView는 한정된 자원인 메모리를 효율적으로 사용하기에 특화된 위젯입니다.
- 이러한 RecyclerView의 Adapter에서는 ViewHolder 패턴을 강제하며 onCreateViewHolder(), onBindViewHolder()를 통해 ViewHolder를 생성하고 참조합니다.
- 예시)
//RecyclerView Adapter
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item:Model){
textView:TextView = itemView.findViewById(R.id.textView)
texView.text = item.text
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_main,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(currentList[position])
}
Multiple ViewHolder
- 필요에 따라 여러가지 형태의 item Layout과 ViewHolder를 활용하여 RecyclerView를 생성할 수도 있습니다.
- 이는 getItemViewType() 함수에서 해당 데이터에 각각의 item에 대한 viewType을 지정해주고 onCreateViewHolder() 내에서 viewType에 따른 ViewHolder를 생성해줌으로써 다중 뷰홀더의 사용이 가능해집니다.
- 개인적인 생각으로 효율적인 Multiple ViewHolder의 사용을 위해서는 체계적인 Data List의 구성이 중요하다고 생각합니다.
- 예시)
class ViewHolder1(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: Model) {
val textView1:TextView = itemView.textView
textView1.text= item.text
}
}
class ViewHolder2(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: Model) {
val textView2:TextView = itemView.textView
textView2.text= item.text
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return when (viewType) {
0 -> {
val view1 = LayoutInflater.from(parent.context).inflate(R.layout.item_main1, parent, false)
ViewHolder1(view1)
}
1 -> {
val view2 = LayoutInflater.from(parent.context).inflate(R.layout.item_main2, parent, false)
ViewHolder1(view2)
}
}
}