[2024. 01. 10] RecyclerView

Gahyeon Lee·2024년 1월 10일
0

TIL

목록 보기
42/47

⭐️ RecyclerView

실무에서 가장 많이 쓰는 AdapterView는 RecyclerView! 반드시 완벽하게 숙지하자!

1. RecyclerView란?

RecyclerView는 안드로이드 앱에서 리스트 형태의 데이터를 표시하는데 사용되는 위젯이다. 여러 아이템을 스크롤 가능한 리스트로 표현하며(가로 스크롤도 가능), 많은 아이템을 효율적으로 관리하고 보여주는 역할을 한다.

  • RecyclerView는 한정적인 화면에 많은 데이터를 넣을 수 있는 View입니다.
  • Recycle을 한국어로 하면 재활용하다라는 뜻. 즉, View를 재활용해서 사용하겠다는 것이다.

2. ListView 와 RecyclerView

1) ListView

  • 사용자가 스크롤 할 때마다 위에 있던 아이템은 삭제되고, 맨 아래의 아이템은 생성 되길 반복한다.
  • 아이템이 100개면 100개가 삭제, 생성된다. 즉, 계속 삭제와 생성을 반복하므로 성능이 좋지 않다.

2) RecyclerView

  • 사용자가 스크롤 할 때, 위에 있던 아이템이 재활용 돼서 아래로 이동하여 재사용 한다.
  • 즉, 아이템이 100개여도 10개정도의 View만 만들고 10개를 재활용해서 사용한다.
  • View를 계속 만드는 ListView의 단점을 보완하기 위해 나왔다.

3. RecyclerView 사용 준비물

  • LayoutManager
  • LayoutManagerRecyclerView 내부의 아이템들이 어떻게 배치될지를 결정한다.
  • 기본 제공되는 LayoutManager로는 LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager 등이 있다.
recyclerView.layoutManager = LinearLayoutManager(this) // 수직 리스트를 위한 LinearLayoutManager
// 또는
recyclerView.layoutManager = GridLayoutManager(this, 3) // 3열 그리드를 위한 GridLayoutManager
  • RecyclerView.Adapter
    RecyclerView는 화면에 보여주는 역할을 하는 뷰이고, 거기에 들어갈 데이터가 필요하다. 뷰와 데이터를 연결해 주어야 한다. 이 연결해 주는 역할을 하는 것이 어댑터이다. RecyclerView 안에 Adapter라는 게 이미 추상화되어서 선언돼있다. 이것을 상속해서 구현하면 된다.

    • Adapter란 데이터 테이블을 목록 형태로 보여주기 위해 사용되는 것으로, 데이터를 다양한 형식의 리스트 형식을 보여주기 위해서 데이터와 RecyclerView 사이에 존재하는 객체이다. 즉, 데이터와 RecyclerView 사이의 통신을 위한 연결체이다.
    • RecyclerView에 표시될 데이터와 해당 데이터를 보여줄 ViewHolder를 연결한다.
    • Adapter는 데이터셋의 변경 사항을 RecyclerView에 알리고, 데이터를 기반으로 뷰를 생성한다.
  • ViewHolder

    • RecyclerView의 기본 단위.
    • RecyclerView의 리스트를 아이템뷰라고 하고 뷰 하나하나를 뷰홀더라고 한다.
    • ViewHolder는 화면에 표시될 데이터나 아이템들을 저장하는 역할을 한다.
    • RecyclerView의 개념을 적용하기 위해서는 스크롤 해서 위로 올라간 View를 재활용해야 한다. 그러려면 이 View를 기억하고 있어야 하는데, ViewHolder가 그 역할을 한다.
    • RecyclerView개별 아이템 뷰를 위한 객체이다.
    • 아이템 뷰의 모든 서브 뷰를 담고 있어 재사용과 성능 최적화에 도움을 준다.
      inner class Holder(val binding: ItemRecyclerviewBinding) : RecyclerView.ViewHolder(binding.root) {    // holder를 만들고 계속해서 재활용
             val iconImageView = binding.iconItem
             val name = binding.textItem1
             val age = binding.textItem2
         }

4. RecyclerView 실습

1) activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
</LinearLayout>

2) data Class 만들기. (MyItem)

data class MyItem(val aIcon:Int, val aName:String, val aAge:String)

3) 어댑터 클래스 정의
앞서 정의한 MyItem타입의 객체들을 ArrayList로 관리하는 MyAdapter클래스를 RecyclerView.Adapter를 파생하여 정의한다.

// MyAdapter.kt
class MyAdapter(val mItems: MutableList<MyItem>) : RecyclerView.Adapter<MyAdapter.Holder>() {    // 인자로 리스트를 넣어주고, RecyclerView의 Adapter를 상속받음. 상속받으면 ItemId, ItemCount를 꼭 오버라이딩해야 한다.

    interface ItemClick {
        fun onClick(view : View, position : Int)
    }

    var itemClick : ItemClick? = null    // itemClick은 타입이 ItemClick

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = ItemRecyclerviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)    // binding을 Holder에 넣어줌
    }

    override fun onBindViewHolder(holder: Holder, position: Int) {    // onBindViewHolder가 8번 돌면서 mItems에 있는 8개를 하나하나 실행시킴(화면에 보이는데까지만 실행됨. 밑으로 스크롤해서 보여질 때 onBindViewHolder가 불림) Holder에 차례대로 들어옴. position은 0번째 부터 들어옴
        holder.itemView.setOnClickListener {  //클릭 이벤트 추가 부분
            itemClick?.onClick(it, position)
        }
        holder.iconImageView.setImageResource(mItems[position].aIcon)
        holder.name.text = mItems[position].aName
        holder.age.text = mItems[position].aAge
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

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

    inner class Holder(val binding: ItemRecyclerviewBinding) : RecyclerView.ViewHolder(binding.root) {    // holder를 만들고 계속해서 재활용
        val iconImageView = binding.iconItem
        val name = binding.textItem1
        val age = binding.textItem2
    }
}
  • onCreateViewHolder
    1. 메서드 정의: onCreateViewHolder는 ViewHolder 객체를 생성하는 메서드이다. 이 메서드는 RecyclerView.Adapter에 정의되어 있으며, 각 아이템을 위한 View를 생성하고 그 View를 감싸는 ViewHolder 객체를 반환한다.
    2. 매개변수:
      • parent: ViewGroup: 이 매개변수는 ViewHolder가 결국에 추가될 ViewGroup을 의미한다. 대부분의 경우, 이것은 RecyclerView 자체이다.
      • viewType: Int: 이 매개변수는 다양한 뷰 타입을 구별하는 데 사용된다. 하나의 RecyclerView에서 다양한 레이아웃을 보여줘야 할 때 유용하다.
    3. LayoutInflater를 이용한 뷰 생성:
      • LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false): 이 코드 라인은 XML 레이아웃 파일(item_view.xml)을 실제 View 객체로 변환한다. LayoutInflater는 XML을 실제 View 객체로 인플레이션하는데 사용된다.
      • parent.context: 현재의 Context를 가져오는 방법.
      • inflate 메서드는 세 가지 매개변수를 받는다:
        • 첫 번째는 XML 레이아웃 파일의 리소스 ID이고,
        • 두 번째는 이 뷰가 추가될 부모 뷰그룹으로, 여기서는 false로 설정되어 있어 부모 뷰그룹에 바로 추가되지 않고, 나중에 RecyclerView에 의해 추가된다.
    4. ViewHolder 생성 및 반환:
      • MyViewHolder(itemView): 여기서 MyViewHolderRecyclerView.ViewHolder를 상속받은 사용자 정의 클래스이다. 이 클래스는 레이아웃 내의 뷰들을 캐싱하고 재사용한다.
      • return MyViewHolder(itemView): 생성된 MyViewHolder 인스턴스를 반환한다. RecyclerView는 이 ViewHolder를 사용하여 각 아이템의 데이터를 바인딩하고 화면에 표시한다.

4) MainActivity

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // 데이터 원본 준비
        val dataList = mutableListOf<MyItem>()    // data Class를 만들고(MyItem), dataList에 샘플 데이터들을 추가한다. 지금은 샘플 데이터를 쓰지만, 실제 프로젝트 진행할 떄는 네트워크를 통해 서버에서 데이터를 받아올 것이다.
        dataList.add(MyItem(R.drawable.sample_0, "Chopa", "9"))
        dataList.add(MyItem(R.drawable.sample_1, "Chopa", "9"))
        dataList.add(MyItem(R.drawable.sample_2, "Chopa", "9"))
        dataList.add(MyItem(R.drawable.sample_3, "Duckman", "8.5"))
        dataList.add(MyItem(R.drawable.sample_4, "Duckman", "8.5"))
        dataList.add(MyItem(R.drawable.sample_5, "Duckman", "8.5"))
        dataList.add(MyItem(R.drawable.sample_6, "Ddakji", "5"))
        dataList.add(MyItem(R.drawable.sample_7, "Ddakji", "5"))

        val adapter = MyAdapter(dataList)    // adapter는 MyAdapter이고, 그 안에 실제로 보여줄 dataList를 넣음.
        binding.recyclerView.adapter = adapter
        binding.recyclerView.layoutManager = LinearLayoutManager(this)    // layoutManager는 레이아웃을 어떻게 구성할건지.

        adapter.itemClick = object : MyAdapter.ItemClick {
            override fun onClick(view: View, position: Int) {
                val name: String = dataList[position].aName
                Toast.makeText(this@MainActivity," $name 선택!", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
profile
코린이 강아지 집사🐶

0개의 댓글