앱개발을 하다보면 다음 사진과 같이 반복되는 형식의 뷰를 나열해야 하는 경우가 있다.
사진에서는 특정 사용자의 프로필 사진, 이름 접속 상태 등이 반복적으로 나타난다. 이러한 뷰를 우리는 리스트(list)라고 한다. 그리고 안드로이드에서는 리스트뷰(List View)를 통해 이를 구현할 수 있다.
그런데 안드로이드 공부를 하다보면 리스트뷰 대신 리사이클러뷰를 사용하는 것이 좋다는 의견을 많이 듣는다. 왜그럴까? 항상 어떤 기술이 왜 사용되는지에 대해 알아볼 필요가 있다.
안드로이드 제트팩의 한 요소인 리사이클러뷰 안드로이드 공식문서를 들여다보면 (항상 공식문서를 중심으로 공부하고 서칭하는 것이 좋다.) 화면에서 스크롤된 뷰가 재사용된다고 나온다. 즉, 어차피 같은 형식의 뷰이니 밑으로 내리면서 사라진 뷰를 안의 내용만 바꿔서 재사용한다는 것이다.
-> 뷰를 재사용하면 앱의 응답성을 개선하고 전력 소모를 줄이기 때문에 성능이 개선된다. 따라서 기존의 리스트뷰 대신 리사이클러뷰를 사용한다.
그렇다면 리사이클러뷰는 어떻게 사용하는지에 대해 알아보자. 개인적으로 처음 리사이클러뷰를 접했을 때는 굉장히 어렵고 복잡하다고 느꼈다. 근데 코드를 한줄한줄 파악하면서 따라하다보면 어느새 적응이 된다.
- 반복되는 뷰를 만든다. 맨 위의 사진인 카카오톡 친구 목록을 예를 들면 밑의 사진과 같은 형식이 반복됨을 알 수 있다. 안드로이드 스튜디오의 res->layout 패키지 안에 반복되는 뷰의 xml파일을 만든다. 보통 이렇게 반복되는 뷰의 이름은 item을 붙이는 경우가 많다.
- 반복되는 뷰가 나타날 xml파일에 리사이클러뷰를 추가한다. 원하는 위치에 다른 뷰처럼 추가하면 된다.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/scrap_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/history_title_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="10dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_idea_list_recyclerview"
/>
여기서 중요한 것은 아까 만든 item~.xml파일을 반복시킬 것이라는 것을 리사이클러뷰에게 알려주어야 한다. 따라서 tools:listitem에 아까 만든 item~.xml파일을 연결해준다. 또한 app:layoutManager를 통해 어떤 수직으로 나열할 것인지 그리드 형태로 나열할 것인지 등을 선택할 수 있다. 이는 검색을 통해 본인에게 맞는 것을 선택해 쓰면 된다.
- 여기서부터 복잡하다. 바로 adapter와 viewholder를 만드는 것이다. 공식문서에 따르면 ViewHolder는 목록에 있는 개별 항목의 레이아웃을 포함하는 View의 래퍼, Adapter는 필요에 따라 ViewHolder 객체를 만들고 이러한 뷰에 데이터를 설정하는 것이라고 나온다. 말이 좀 어려운데, 쉽게 말해서 viewholder를 통해 1번에서 만든 item.xml에 들어갈 요소 즉, 프로필 사진, 이름, 활동 상태 등의 뷰에 서버에서 받아온 데이터나 직접 입력한 데이터를 넣어준다. 그리고 adpater는 이러한 데이터를 viewholder에 넣어주기 위한 중간 다리 역할을 한다고 생각하면 된다. 안드로이드 프로젝트에서 새로운 코틀린 파일을 만들고 다음과 같은 코드를 이용한다.
// 여기서 dataSet의 형식은 본인이 서버에서 데이터를 GET해서 오는 것이라면 reponsedata를, 직접 만든 데이터클래스를 사용하고 싶으면 dataclass의 이름을 넣으면 된다.
class CustomAdapter(private val dataSet: Array<String>) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
// 뷰홀더를 만들고 뷰를 초기화하는 함수이다. 아직 바인딩이 안되었기 때문에 뷰에 내용이 직접적으로 담기는 과정은 아니다.
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.text_row_item, viewGroup, false)
return ViewHolder(view)
}
// 여기서 뷰와 데이터의 결합이 이루어진다. 만약 이미지 url을 가져오면 이 함수에서 url을 뷰에 넣어서 사진을 출력할 수 있다.(단, 이미지는 Glide와 같은 외부 라이브러리 사용을 추천)
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
// 이런식으로 글자를 넣을 수도 있다.
viewHolder.textView.text = dataSet[position]
}
// 총 몇개의 반복되는 뷰 데이터가 있는지, 즉 친구목록에서 총 친구가 몇 명인지와 같다.
override fun getItemCount() = dataSet.size
}
- 어뎁터와 뷰홀더를 만들었으면 리사이클러뷰를 사용하는 xml과 연결된 kt파일로 가서 리사이클러뷰를 객체 참조한다. findViewById를 쓰거나 뷰 바인딩으로 참조하면된다. 그리고 참조한 리사이클러뷰의 어댑터를 작성한 어댑터로 바꾸어준다.
binding.myRecyclerView.adapter = CustomAdapter()
그리고 원하는 데이터를 넣은 뒤 데이터가 변경되었다는 것을 알려주기 위해서 다음과 같이 어댑터에게 알려주는 코드를 사용한다. 즉, 이 코드를 통해 리사이클러뷰를 갱신할 수 있다.
CustomAdapter().notifyDataSetChanged()
사실 리사이클러뷰는 안드로이드의 기본 중 하나이고 다른 블로그에 너무나 정리가 잘되어있어서 나만의 필기용으로 정리했다. (혹시라도 안드로이드 처음 하는 분이거나 도움이 필요하신 분이라면 댓글로 질문 남겨주시면 최대한 도와드리겠습니다.)
프로젝트를 하다보면 리사이클러뷰가 정말 굉장히 많이 쓰인다. 근데 위의 친구목록처럼 같은 형태로 반복되는 경우도 있지만 아닌 경우도 많다. 내가 프로젝트에서 사용했던 활용을 공유해보자고 한다.
- 채팅과 같은 리사이클러뷰
채팅은 상대방의 메시지와 나의 메시지로 구성이 된다.일반적으로 상대방의 메시지의 경우 왼쪽에 말풍선과 같은 ChatView가 나타나있고 내가 보낸 메시지의 경우 오른쪽에 ChatView가 나타나고 둘의 색 또한 다르다. 하지만 동적으로 계속해서 리스트가 추가된다. 즉, 리사이클러뷰를 이용해야 한다. 이럴때는 어떻게 할까?
-> 하나의 adapter 안에 viewholder를 2개 만든다. 하나의 뷰홀더에는 상대방의 메시지를 상대방 ChatView에 넣는 작업을 하고 하나의 뷰홀더에는 나의 메시지를 나의 ChatView에 넣는 작업을 한뒤, onBindViewHolder에서 어떠한 뷰홀더를 사용할 것인지 결정한다. 나 같은 경우는 메시지 작성자의 아이디를 나의 아이디와 비교해 상대방인지 나인지 결정했다.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(messageList[position].senderId== userNickName){
(holder as MyChatViewHolder).onBind(messageList[position])
holder.setIsRecyclable(false)
}
else{
(holder as ChatViewHolder).onBind(messageList[position])
holder.setIsRecyclable(false)
}
}
- 중첩 리사이클러뷰
ToDo 리스트같은 앱을 만들다보면 날짜를 기준으로 날짜 밑에 내가 적은 할일들이 쭉 나열되는 것을 구현해야 될 때가 있다. 즉, 날짜들도 리사이클러뷰로 구현해야하고 해당 날짜에 할 일들도 리사이클러뷰 형태로 구현해야한다. 이러한 것을 중첩 리사이클러뷰라고 부른다. 이 때는 그냥 리사이클러뷰를 두 개 만든다고 생각하면 된다. adpater도 2개 만들어야한다. 그 후 날짜 리사이클러뷰(즉, 범위가 더 큰 리사이클러뷰)의 어댑터의 뷰홀더에서 바인딩한 리사이클러뷰의 어댑터를 작은 범위의 리사이클러뷰 어댑터로 설정하면 된다.