[Android][Kotlin] 코틀린 ViewHolder 뷰홀더
by Yena Choi
Study Note
ViewHolder의 필요성
ListView에서 발견된 문제점은, 스크롤을 움직이는 등 View가 보이거나 사라지면 그 때마다 findViewById
를 통해 convertView에 들어갈 요소를 찾는다는 점이었다. 스크롤 할 때마다 View를 찾으면 리소스를 많이 사용하게 되고, 속도가 느려진다. ViewHolder
를 이용하면 이 View의 재활용(recycle)이 가능하다.
ViewHolder 활용
ListView의 각 View와 실제 데이터를 매칭하는 것이 Adapter의 역할이다. 따라서 ViewHolder를 사용하려면 Adapter 내에 설정해야한다.
이전 ListView 포스트에 이어, Dog List 화면을 만들기 위해 사용했던 커스텀 어댑터인 MainListAdapter 클래스를 다시 사용했다. MainListAdapter의 맨 끝에 private class
인 ViewHolder Class를 만들어 각 View요소를 null로 선언했다.
class MainListAdapter (val context: Context, val dogList: ArrayList<Dog>) : BaseAdapter() {
override fun getView(...)
override ...
...
private class ViewHolder {
var dogBreed : TextView? = null
var dogAge: TextView? = null
var dogGender: TextView? = null
var dogPhoto : ImageView? = null
}
}
이 ViewHolder는 getView
메소드를 override 할 때 사용한다. getView 설정을 할 때, ViewHolder 안에 데이터가 아무것도 없으면 findVidwById 하여 ListView의 View를 생성하고, ViewHolder 안에 데이터가 있을 경우 이를 재활용 하도록 설정한다.
ViewHolder까지 설정한 MainListAdapter의 최종 모습은 아래와 같다.
class MainListAdapter (val context: Context, val dogList: ArrayList<Dog>) : BaseAdapter() {
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view : View
val holder : ViewHolder
if (convertView == null) {
view = LayoutInflater.from(context).inflate(R.layout.main_lv_item, null)
holder = ViewHolder()
holder.dogBreed = view.findViewById(R.id.dogBreed)
holder.dogAge = view.findViewById(R.id.dogAge)
holder.dogGender = view.findViewById(R.id.dogGender)
holder.dogPhoto = view.findViewById(R.id.dogPhoto)
view.tag = holder
/* convertView가 null, 즉 최초로 화면을 실행할 때에
ViewHolder에 각각의 TextView와 ImageView를 findVidwById로 설정.
마지막에 태그를 holder로 설정한다. */
} else {
holder = convertView.tag as ViewHolder
view = convertView
/* 이미 만들어진 View가 있으므로, tag를 통해 불러와서 대체한다. */
}
val dog = dogList[position]
val resourceId = context.resources.getIdentifier(dog.photo, "drawable", context.packageName)
holder.dogPhoto?.setImageResource(resourceId)
holder.dogBreed?.text = dog.breed
holder.dogAge?.text = dog.dogAge
holder.dogGender?.text = dog.gender
/* holder와 실제 데이터를 연결한다. null일 수 있으므로 변수에 '?'을 붙여 safe call 한다. */
return view
}
override fun getItem(position: Int): Any {
return dogList[position]
}
override fun getItemId(position: Int): Long {
return 0
}
override fun getCount(): Int {
return dogList.size
}
private class ViewHolder {
var dogBreed : TextView? = null
var dogAge: TextView? = null
var dogGender: TextView? = null
var dogPhoto : ImageView? = null
}
}