Android 리사이클러 뷰

김성준·2022년 3월 4일
0

안드로이드

목록 보기
12/16

리사이클러 뷰(Recycler View)

RecyclerView를 사용하면 대량의 데이터 세트를 효율적으로 표시할 수 있습니다. 개발자가 데이터를 제공하고 각 항목의 모양을 정의하면 RecyclerView 라이브러리가 필요할 때 요소를 동적으로 생성합니다.

RecyclerView는 화면에서 스크롤된 새 항목의 뷰를 재사용합니다. 이렇게 뷰를 재사용하면 앱의 응답성을 개선하고 전력 소모를 줄이기 때문에 성능이 개선됩니다.

리사이클러 뷰의 구성요소

- 뷰홀더(ViewHolder)
- 어댑터(Adapter)
- 레이아웃 매니저(LayoutManager)

뷰홀더(ViewHolder)

한마디로 설명하면 각 뷰를 보관하는 Holder 객체로 이야기 할 수 있습니다.
"ListView / RecyclerView 는 inflate를 최소화 하기 위해서 뷰를 재활용 하는데, 이 때 각 뷰의 내용을 업데이트 하기 위해 findViewById 를 매번 호출 해야합니다. 이로 인해 성능저하가 일어남에 따라 ItemView의 각 요소를 바로 엑세스 할 수 있도록 저장해두고 사용하기 위한 객체입니다." 정도로 설명할 수 있을 것 같습니다.

어댑터(Adapter)

데이터를 받아서 관리하고 어댑터가 연결된 뷰에서 출력할 수 있는 형태로 그 데이터를 다시 제공하는 역할을 합니다.

리사이클러 뷰의 구현 단계

  1. 리사이클러 뷰 레이아웃에 추가.

  2. 리사이클러 뷰 내에서 사용할 아이템 레이아웃 생성.

  3. 뷰홀더 클래스 구현.

  4. 어댑터 클래스 구현.

  5. 리사이클러뷰에 어댑터 적용.

1. 리사이클러 뷰를 레이아웃에 추가.


레이아웃의 디자인 탭에서 추가하고 싶은곳에 리사이클러 뷰를 드래그해서 추가합니다.

2. 리사이클러 뷰 내에서 사용할 아이템 레이아웃 생성.

리사이클러 뷰 내에서 반복적으로 사용할 아이템 레이아웃을 생성합니다.

3. 뷰홀더 클래스 구현

class MyViewHolder private constructor (itemView: View): RecyclerView.ViewHolder(itemView) {
    val idxText = itemView.findViewById<TextView>(R.id.idx_text)
    val nameText = itemView.findViewById<TextView>(R.id.name_text)
    val ageText = itemView.findViewById<TextView>(R.id.age_text)

    fun bind(data: Data) {
        idxText.text = data.idx
        nameText.text = data.name
        ageText.text = data.age
    }

    companion object {
        fun from(parent: ViewGroup): MyViewHolder {
            val layoutInflater = LayoutInflater.from(parent.context)
            val itemView = layoutInflater.inflate(R.layout.recycler_item_layout, parent, false)
            return MyViewHolder(itemView)
        }
    }
}

아이템 레이아웃의 뷰를 포함하는 뷰홀더 클래스를 구현합니다.

4. 어댑터 클래스 구현

class RecyclerAdapter(val item: MutableList<Data>): RecyclerView.Adapter<MyViewHolder>() {
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.bind(item[position])
    }

    override fun getItemCount(): Int {
        return item.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        return MyViewHolder.from(parent)
    }

    fun add() {
        item += Data((item.size + 1).toString(), "seongjki", (item.size + 19).toString())
        notifyItemChanged(itemCount)
    }
}

뷰홀더를 생성하고 그에 맞는 데이터를 바인딩하는 어댑터 클래스를 생성합니다.

5. 리사이클러 뷰에 어댑터와 레이아웃 매니저 적용.

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        val items = mutableListOf<Data>()
        val adapter = RecyclerAdapter(items)
        binding.recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        binding.recyclerView.adapter = adapter
        binding.button.setOnClickListener {
            adapter.add()
        }
    }
}

ViewHolder 클래스에서 findViewById 대신 뷰 바인딩 사용하기

findViewById는 뷰그룹에서 해당 id와 일치하는 뷰를 찾을 때까지 뷰그룹을 모두 탐색하는 함수 입니다.

따라서 뷰그룹 안에 또 뷰그룹이 있는 등, 복잡하게 구성된 레이아웃에서 사용될 경우 성능 저하를 일으킬 가능성이 있습니다.

findViewById의 성능저하 알아보기

이런 경우, findViewById 대신 뷰바인딩이나 데이터바인딩을 사용하면 이전에 설명한 문제를 예방할 수 있습니다.

아래는 바인딩을 사용해 findViewById를 대체한 코드의 예제입니다.

class MyViewHolder private constructor (binding: RecyclerItemLayoutBinding): RecyclerView.ViewHolder(binding.root) {
    val idxText = binding.idxText
    val nameText = binding.nameText
    val ageText = binding.ageText

    fun bind(data: Data) {
        idxText.text = data.idx
        nameText.text = data.name
        ageText.text = data.age
    }

    companion object {
        fun from(parent: ViewGroup): MyViewHolder {
            val layoutInflater = LayoutInflater.from(parent.context)
            val binding = RecyclerItemLayoutBinding.inflate(layoutInflater, parent, false)
            return MyViewHolder(binding)
        }
    }
}

출처

소스코드 요리사
안드로이드 공식 가이드
안드로이드 공식 코드랩
안드로이드 맛보기
WonseokOh의 velog

profile
수신제가치국평천하

0개의 댓글