recycle
1. (폐품을) 재활용하다
2. (같은 생각, 방법 등을) 다시 이용하다
그렇다면 리사이클러 뷰에서 중요한 점은 다음과 같을 것이다.
이런 문제를 해결해나가면서 문제를 해결하도록 하자. 필자가 제작했던 뷰를 베이스로 하여 리사이클러뷰를 제작해보자.
item_product_review.xml
반복되는 형태의 틀을 기존 Layout 제작하는 방식과 마찬가지로 동일하게 제작하면 된다. Constraint, Relative 등 Layout의 종류에 얽매이지 않고 제작하면 된다.
<androidx.recyclerview.widget.RecyclerView
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:orientation="vertical"
레이아웃매니저를 LinearLayoutManager로 설정하고 배열방식을 vertical로 설정하면 데이터들을 리스트형식으로 배열한다
app:layout_constraintTop_toBottomOf="@+id/spn_search_goods_filter"
listitem을 적용하면 리사이클러뷰 내에서 위의 Layout 형태로 뷰를 미리볼 수 있음
tools:listitem="@layout/item_search_main_goodssearch" />
data class는 말 그대로 "데이터의 형태"를 결정시켜주는 틀의 기능을 하는 클래스라 보면 된다. 이런 데이터 클래스는
등의 함수를 자동으로 생성할 수 있게 한다.
위의 Layout에는 사진, 제품 이름, 나이, 제품 리뷰, 평점, 하트 등의 데이터가 들어가야 하므로 필자는
data class LayoutData (
val img_goods : String,
val tv_goods : String,
val tv_age : String,
val tv_review : String,
val tv_star : Float,
val tv_heart : Float
)
의 형식으로 데이터 클래스를 작성했을 것이다.
이제 반복적으로 데이터가 들어갈 틀과, 들어갈 데이터의 형식이 결정되었다. 그러나 이 둘을 연결을 시키는 과정이 지금까지 내용에서 다룬적이 없다.
이런 기능을 처음 구현한다고 하면 각 아이템 마다 뷰를 찾아서(findViewById
함수 이용하겠죠) 데이터를 일일이 매칭을 할 것이다. 그게 가장 간편하고 쉽게 떠올릴 수 있는 방안이기 때문이다.
그러나 RecyclerView에서는 ViewHolder라는 아주 획기적인 방법으로 노가다는 줄이고 효율성을 극대화하여 위의 기능을 구현할 수 있다.
ViewHolder는 클래스 내에 View를 저장하는 변수를 만들어 그 안에 데이터를 직접 연결시킬 수 있는 클래스, 디자인 패턴을 말 말한다. 아마 이렇게 말하면 이해가 한 번에 와닿지 않는 독자들이 많을 것이다. 왜냐하면 내가 그랬기 때문이다. 그림으로 다시 보자
위와 같이 내가 넣고자 하는 데이터(데이터 클래스 형식으로 저장된 변수)를 실제 레이아웃의 데이터로 연결시키는 기능을 하는 것이 ViewHolder이다.
그럼 ViewHolder에서는 다음과 같은 것들이 필요할 것이다.
그럼 ViewHolder 클래스는 다음과 같은 형식으로 작성할 수 있다. 물론 1, 2 외에도 필요한 것이 있지만 우선 위의 사항들을 중점으로 클래스를 분석해보자
class MyViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding,root) {
//View와 데이터를 연결시키는 함수
fun bind(layoutData : LayoutData){
binding.tvGoods.text = layoutData.tv_goods
...
}
위와 같이 데이터들을 View에 넣을 수 있다.
지금까지 한 것을 정리하면
이와 같은데, 이제는 ViewHolder에서 정의한 기능을 실제로 사용할 수 있는 구현체를 만들어야 한다. 즉, 데이터를 받아오고 이를 레이아웃에 직접 연결하는 함수를 실행시키는 클래스를 만들어야 한다는 말이다. 이런 역할을 하는 클래스를 Adapter라 한다.
그럼 Adapter에서는 1) ViewHolder에 담길 데이터들(List 형태의 데이터들) 2) 데이터들과 레이아웃을 묶을 수 있게 레이아웃을 inflate할 수 있는 함수 등이 있어야 할 것이다. 이런 기능은 RecyclerView.Adapter 제너릭(구현된 ViewHolder에 맞춰서) 클래스에 존재하기에 우리가 사용할 어댑터는 이를 상속받으면 된다. 다음과 같이 구현해보자
//ViewHolder에 맞춰서 Adapter가 구현된다
class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>(){
//데이터들을 저장하는 변수
private var data = mutableListOf<LayoutData>()
class MyViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding,root) {
//View와 데이터를 연결시키는 함수
fun bind(layoutData : LayoutData) {
binding.tvGoods.text = layoutData.tv_goods
...
}
//상속받으면 자동 생성
//ViewHolder에 쓰일 Layout을 inflate하는 함수
//ViewGroup의 context를 사용하여 특정 화면에서 구현할 수 있도록 함
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeatureViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate(layoutInflater, R.layout.item_product_review, parent, false)
return MyViewHolder(binding)
}
//상속받으면 자동 생성
override fun getItemCount(): Int = data.size
//상속받으면 자동 생성
//ViewHolder에서 데이터 묶는 함수가 실행되는 곳
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.onBind(data[position])
}
fun replaceList(newList: MutableList<LayoutData>) {
data = newList.toMutableList()
//어댑터의 데이터가 변했다는 notify를 날린다
notifyDataSetChanged()
}
}
RecyclerView의 어댑터는 위와 같이 구현할 수 있다.
우선 1) 어댑터를 만들고 2) 데이터를 어댑터 안에다 넣어야한다.
그리고 3) 어댑터 안에 데이터가 바뀌었다는 notify를 하고 4) 실제 RecyclerView의 어댑터를 만든 어댑터로 설정한다.
val mDatas = mutableListOf<LayoutData>()
//어댑터를 생성한다
myAdapter = MyAdapter()
//데이터를 생성해야한다(서버통신을 안 할 경우 이렇게)
mDatas.apply(
add(
LayoutData(
...
)
)
add(
LayoutData(
...
)
)
...
)
//데이터를 어댑터 안에 넣는다
myAdapter.replaceList(mDatas)
//실제 RecyclerView의 adapter를 만든 adapter로 설정한다
binding.rvMyRecyclerView.adapter = myAdapter
위와 같은 설정을 끝내면 RecyclerView의 작동이 정상적으로 잘 될 것이다.
아마 안드로이드를 처음 공부할 때 제일 먼저 마주치는 고비가 RecyclerView일텐데, 이 게시글이 어려움을 벗어나는데 조금이나마 도움이 되었으면 필자는 바라고 있다.
ViewHolder로 읽기 좋은 코드를 구현하고 싶어서 구글링 하던 중 보고 들어왔어요. 한 수 배우고 갑니다^^