Android

(Android Studio) - RecyclerView 사용 방법

돗개진 2024. 4. 16. 21:32

 

[ RecyclerView ]

 

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

 

- RecyclerView 는 한정적인 화면에 많은 데이터를 넣을 수 있는 View 임

- Recycle 을 해석하면 재활용하다라는 의미로 재사용을 하기 위해 사용됨

 

 

 

[ ListView 와 RecyclerView ]

 

ListView

- 사용자가 스크롤 할 때마다 위에 있던 아이템은 삭제되고 맨 아래의 아이템은 생성되는 것을 반복

- 아이템이 100개면 100개의 아이템들이 삭제되고 생성되는 것을 반복하여 성능이 좋지 않음

 

 

 

 

RecyclerView

- 사용자가 스크롤 할 때 위에 있던 아이템을 재활용하여 아래로 이동되기 때문에 재사용하게 됨

- 아이템이 100개여도 10개 정도의 View 만 만들고 10개를 재활용해서 사용함

- View 를 계속 만드는 ListView 의 단점을 보완하기 위해 생김

 

 

 


 

[ RecyclerView 사용법 ]

 

1) Adapter

- 데이터 테이블을 목록 형태로 보여 주기 위해 사용되는 것으로 데이터를 다양한 형식의 리스트 형식을 보여 주기 위해서 데이터와 RecyclerView 사이에 존재하는 객체

 

=> 데이터와 RecyclerView 사이의 통신을 위한 연결체

 

 

2) ViewHolder

- ViewHolder 란 화면에 표시될 데이터나 아이템들을 저장하는 역할을 함

- RecyclerView 의 개념을 적용하기 위해서 스크롤해서 위로 올라간 View를 재활용해야 하는데 이 때의 View 를 기억하고 있어야 하고 이 역할을 ViewHolder 가 함

 

 

3) RecyclerView 예제

 

먼저, 메안 화면에 대한 레이아웃 작업이 끝났다면 RecyclerView 가 들어갈 곳에 담길 item 의 UI 를 작업해 줘야 한다.

 

< item_recyclerview.xml >

item_recyclerview.xml - RecyclerView 로 들어갈 Item 의 UI

 

 

 

 

 

recyclerview의 item들이 어떤 속성의 데이터들을 가지고 있을지 데이터 타입과 이름을 선언하는 데이터 클래스를 생성해 준다. 아래에서 companion object 로 다른 변수들을 생성해 준 이유는 멀티 뷰 타입 recyclerview 를 사용해 보기 위함이다.

 

< data.kt >

data class CardInfo(val type: Int, val name: String, val num: String, val data: String, val price: Double) {
    companion object {
        const val BLUE_TYPE = 0
        const val SKY_TYPE = 1
        const val ORANGE_TYPE = 2
    }
}

 

 

 

 

 

메인 화면과 item 에 대한 전반적인 레이아웃 작업이 끝나고 데이터 클래스를 생성하여 데이터 타입을 설정했다면  Adapter를 만들어 줘야 한다. 어댑터를 만들 때는 필수적으로 오버라이딩 (재정의) 해야 하는 메소드들이 있다.

 

< MultiViewAdapter.kt >

class MultiViewAdapter(private val list: List<CardInfo>) : RecyclerView.Adapter<MultiViewAdapter.CardViewHolder>() {

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

    var itemClick : ItemClick? = null

   // 뷰가 만들어질 때 호출되는 메소드
   // 멀티 뷰 타입을 구현하기 위해서 when 절을 이용하여 viewType 에 따라 다른 item 을 화면에 출력하도록 했다
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MultiViewAdapter.CardViewHolder {
        val view: View?
        return when (viewType) {
            CardInfo.BLUE_TYPE -> {
                view = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview, parent, false)
                CardViewHolder(view)
            }
            CardInfo.SKY_TYPE -> {
                view = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview2, parent, false)
                CardViewHolder(view)
            }
            CardInfo.ORANGE_TYPE -> {
                view = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview3, parent, false)
                CardViewHolder(view)
            }
            else -> throw RuntimeException("알 수 없는 뷰 타입")
        }
    }

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

    override fun getItemViewType(position: Int): Int {
        return list[position].type
    }

   // 뷰가 바인드 될 때 호출되는 메소드
   // 뷰에 내용이 씌워질 때. 즉 스크롤을 내리거나 올릴 때
    override fun onBindViewHolder(holder: MultiViewAdapter.CardViewHolder, position: Int) {
        holder.itemView.setOnClickListener {
            itemClick?.onClick(it, position)
        }

        holder.name.text = list[position].name
        holder.number.text = list[position].num
        holder.date.text = list[position].data

        val decimalFormat = DecimalFormat("$#,###.00")
        holder.price.text = decimalFormat.format(list[position].price)
    }

   // 어댑터 클래서 외부 혹은 내부에 RecyclerView.CardViewHolder 클래스를 상속하여 만듦
   // 각 뷰들을 id 나 itemview 를 통해서 연결시킴
    inner class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val name: TextView = itemView.findViewById(R.id.tv_name)
        val number: TextView = itemView.findViewById(R.id.tv_cardnum)
        val date: TextView = itemView.findViewById(R.id.tv_date)
        val price: TextView = itemView.findViewById(R.id.tv_balance)

        init {
            itemView.setOnClickListener {
                itemClick?.onClick(it, adapterPosition)
            }
        }
    }

}

 

 

 

 

어댑터에 대한 설정이 끝났다면 메인 액티티비티와 어댑터를 연결하는 작업, 데이터들을 추가하는 작업, 데이터를 보내는 작업 등 다양한 작업을 해 줘야 한다.

 

< MainActivity.kt >

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 = listOf(
            CardInfo(
                CardInfo.BLUE_TYPE,
                "Anderson",
                "2423  3581  9503  2412",
                "21 / 24", 3100.30
            ),
            CardInfo(
                CardInfo.SKY_TYPE,
                "Anderson",
                "2423  3581  9503  2412",
                "12 / 25",
                3100.30
            ),
            CardInfo(
                CardInfo.ORANGE_TYPE,
                "Anderson",
                "2423  3581  9503  2412",
                "21 / 24",
                3100.30
            )
        )
	   
       // 데이터 리스트를 사용해 어댑터를 만듦
        val adapter = MultiViewAdapter(dataList)
        
        // 아이템이 클릭되었을 때 intent 와 bundle 을 사용해서 다음 액티비티로 데이터 전달
        adapter.itemClick = object : MultiViewAdapter.ItemClick {
            override fun onClick(view: View, position: Int) {
                val selectedItem = dataList[position]

                val intent = Intent(this@MainActivity, DetailActivity::class.java)
                val bundle = Bundle().apply {
                    putString("name", selectedItem.name)
                    putString("num", selectedItem.num)
                    putString("date", selectedItem.data)
                    putDouble("price", selectedItem.price)
                }
                intent.putExtra("bundle", bundle)
                startActivity(intent)
            }
        }

	   // 리사이클러뷰에 어댑터를 붙여주고 레이아웃 매니저를 성정해 줌
        binding.recyclerView.adapter = adapter
        binding.recyclerView.layoutManager = LinearLayoutManager(this)

    }
}

 

 


 

 

[ 최종 결과물 ]

 

ㄴ> 화면 하단의 카드들이 recyclerview 를 사용한 것이다. 해당 item 들을 클릭하면 MainAcitivty 에서 DetailActivity 로 전환되며 해당 item 이 갖고 있는 데이터를 bundle 로 묶어 전달한다.

 

 

ㄴ> 해당 item 의 데이터가 DetailActivity 로 잘 넘어온 모습이다. intent의 putExtra() 를 사용해서 데이터를 전달하는 방법밖에 사용해 보지 않았는데 bundle 을 통해 putString, putDouble ... 등 타입으로 지정해서 데이터를 묶어서 전달하는 방식을 사용해 보니 훨씬 편리한 것 같다.