ViewHolder 패턴은 findViewById()를 계속하여 호출하는 것을 근본적으로 막기 위해 ViewHodler라는 디자인 패턴이 등장했다. ViewHolder라는 이름을 사전적으로 해석해보면 View를
받친다 or 담아준다 이러한 의미인데 쓰이는 방법 또한 그러하다.
이 전의 글인 Adapter에서 findViewById()는 ViewGroup에서 반복적인 작업을 수행하기 때문에 비용이 많이 든다고 설명했었다. ListView인든 RecyclerView에서든 ViewHolder를 사용하면 한 번 생성하여 저장했던 View는 다시 findViewById()를 통해 View를 불러올 필요가 없어진다.
class ListViewHolder(
val root: View
) {
val textView: TextView = root.findViewById(R.id.listViewItemTextView)
val imageView: ImageView = root.findViewById(R.id.listViewItemImageView)
/**
* ViewHolder의 View에 알맞은 data를 binding
* @param data binding할 data
*/
fun bind(data: ListViewModel) {
textView.text = data.content
imageView.load(data.imageUrl)
}
}
ListView에서는 ViewHolder를 직접 클래스를 만들어서 구현을 하면된다.
override fun getView(position : Int, convertView : View?, parent: ViewGroup?) : View?
{
var convertView = convertView
val viewHolder = ViewHolder
if(converView == null){
convertView = LayoutInflater.from(context).inflate(R.....,parent,false)
viewHolder = ViewHolder()
viewHodler.rideTarget = view.findViewById<TextView>(R.id.Taxi)'
convertView.tag = viewHolder
} else{
viewHolder = convertView.tag as ViewHolder
}
viewHolder.ride!!.text = rideList[position].title
return convertView
override fun getItem(position: Int) : Any{
return rideList[position]
}
override fun getItemId(position : Int) : Long{
Not Yet
}
override fun getCount() : Int {
return rideList.size
}
앞에 작성한 ViewHolder 클래스를 getView에 적용하여 convertView가 없다면 새로운 View를 inflate하고 ViewHolder를 생성하여 View의 tag에 ViewHolder를 저장한다. 만약 convertView가 존재한다면 이전에 저장한 ViewHolder를 tag에서 가져와 ViewHolder를 사용하게 된다. 이렇게 작성하면 한번 findViewById()를 사용했다면 다시 해당 뷰를 똑같은 방법으로 불러올 필요가 없어지는 것이다.
ListView와는 달리 RecyclerView에서는 ViewHolder의 구현을 강제하고 있기 때문에 Adapter에서 ViewHolder의 생성 data binding , itemSize를 반환해주 면됩니다.
class ModelRecyclerAdapter(
private var modelList: List<Model>
) : RecyclerView.Adapter<RecyclerViewHolder>() {
override fun getItemViewType(position: Int): Int = modelList[position].type.ordinal
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
RecyclerViewHolder(LayoutInflater.from(parent.context)
.inflate(R..... ,parent, false)
)
override fun onBindViewHolder(holder: ModelViewHolder<M>, position: Int) {
holder.bindData(modelList[position] as M)
override fun getItemCount() = modelList.size
}
RecyclerView.Adapter에서 type parameter로 사용할 ViewHolder 클래스를 받고 새로운 ViewHolder를 생성할 때는 onCreateViewHolder를 , 데이터를 binding할때는 onBindViewHolder을 동작한다.
RecyclerViewHolder 클래스의 경우는
class RecyclerViewHolder(
val root: View
) : RecyclerView.ViewHolder(root) {
val textView: TextView = root.findViewById(R.id.listViewItemTextView)
val imageView: ImageView = root.findViewById(R.id.listViewItemImageView)
fun bind(data: Model {
textView.text = data.content
imageView.load(data.imageUrl)
}
}
다음과 같이 작성해주면 된다.
다음 글은 Adapter의 이점에 대해서 작성하도록 하겠습니다. 읽어주셔서 감사합니다.