❮
[Android] RecyclerView 1
20190804
RecyclerView 기초
개념
- 안드로이드에서 리스트 또는 격자 형태로 데이터를 보여주는 UI 작업은 매우 자주 필요하다. RecyclerView는 큰 데이터들을 나타내기에 효과적으로 설계되었다.
- RecyclerView 는 지금 화면에 보이는 아이템들만 처리하고 그린다.
- 화면을 스크롤하면 모든 뷰들은 재활용 된다.
- 어댑터 패턴은 객체가 다른 API와 함께 잘 작동하도록 도와주는 패턴이다. RecyclerView는 어댑터를 이용해서 앱의 데이터를 보여줄 수 있는 형태로 변형해준다. 앱이 어떻게 그 데이터를 저장, 처리하는지를 바꿀 필요가 없다.
준비물
RecyclerView에 데이터를 보여주기 위해서 다음 부품들이 필요하다.
데이터들 |
|
RecyclerView 인스턴스 |
xml 레이아웃 안에 선언하면 된다. |
LayoutManager |
아이템을 조직화해준다. 어떻게 배치할지를 결정한다. app:layoutManager 속성을 이용한다. |
하나의 데이터를 표현할 레이아웃 |
아이템 레이아웃 |
ViewHolder |
아이템 레이아웃에서 정보를 가져와서 코드와 연결시킨다. 뷰를 레퍼런스와 연결한다. |
Adapter |
데이터를 준비하고 ViewHolder에서 어떻게 보여질 지를 정한다. |
구현
LayoutManager 있는 RecyclerView 추가
Show Details
- RecyclerView를 xml 레이아웃에 추가한다.
- 여기서 대화상자가 나오면서 gradle 의존성 추가할 건지를 물어보면 OK를 눌러주자.
- build.gradle(module:app) 에서 다음 코드가 있는지 확인하자.(버전은 다를 수 있다.)
implementation 'androidx.recyclerview:recyclerview:1.0.0'
- 다시 xml 레이아웃으로 돌아와 Text 탭으로 들어가자.
- recyclerview의 xml을 필요한 만큼 수정하자. (id, constraint 속성 등등)
- layoutManager 속성을 추가한다. (여기서는 LinearLayoutManager)
ViewHolder 만들기
Step 1 : 하나의 아이템을 위한 레이아웃을 작성한다.
Step 2 : 뷰 홀더 만들기
Show Details
레이아웃 작성
xml 파일에 레이아웃 작성
뷰 홀더 만들기
RV.VH(View) 를 확장해서 클래스 선언. 파일을 따로 만들어도 되지만 자바 스타일은 1파일 1클래스가 원칙이기 때문에 어댑터 클래스 안에 내부 클래스로 만드는 경우가 많음. 코틀린에서는 그냥 따로 만드는 것도 방법.
어댑터 작성
Step 1 : 어댑터 만들기(핵심)
Step 2 : 어댑터 달기
Show Details
어댑터 작성
- RecyclerView.adapter 를 확장한 어댑터 클래스를 만든다.
RecyclerView는 데이터가 어떻게 변하고 있는지를 모르기 때문에 notifyDataSetChanged() 를 이용해서 데이터에 맞게 모든 리스트를 다시 그리게 해야 한다.
- 에러 표시가 뜨면 alt+enter 를 눌러서 onCreateViewHolder(), getItemCount(), onBindViewHolder() 를 오버라이드 한다.
- getItemCount() 를 작성한다. 보통 data.size가 된다.
- onBindViewHolder() 를 구현한다. 특정한 위치에 하나의 데이터를 위한 뷰를 만들어 주는 함수다. 두 개의 인수를 가진다.
- 하나의 view holder
- bind할 데이터의 position
아래는 간단한 예시
- onCreateViewHolder() 를 구현한다. RecyclerView가 하나의 아이템을 표현할 뷰 홀더가 필요할 때마다 호출된다. 이 함수는 2개의 매개변수를 가지고 하나의 뷰 홀더를 리턴한다.
- parent 매개변수 (항상 RecyclerView가 된다.)
- viewType 매개변수는 같은 RecyclerView에 여러 개의 뷰가 존재할 때 사용된다. (텍스트뷰들, 이미지, 비디오 등등을 같은 RecyclerView에 넣어버린 경우에 어떤 것을 위한 뷰 홀더를 만들지를 결정한다.)
예시
어댑터 달기
RV가 들어있는 코드로 가서 만들어준 어댑터를 달아준다.
사용할 데이터 넣어주기.
코드 리팩토링
뷰 홀더에만 관련된 코드들이 어댑터에 있는 상태이다. 이런 코드들을 ViewHolder 안으로 옮겨서 구조적으로 개선. 뷰 홀더를 보여주는 코드와 관리하는 코드를 결합시키고 onBindViewHolder() 에서 ViewHolder를 어떻게 업데이트하는지 세부 사항을 알게 한다.
앱을 만들 때는 여러 개의 뷰 홀더와 복잡한 어댑터들, 변경점을 만드는 개발자들이 있게 된다. 이런 상황을 대비해서 뷰 홀더에 관련된 모든 것들은 반드시 그 뷰 홀더에만 있도록 만들어야 한다.
onBindViewHolder() 리팩토링
목적 : 보여지는 것은 바뀌지 않지만 더 쉽고 안전한 작업을 하도록 도와준다.
- onBindViewHolder에서 item 선언을 제외한 모든 코드를 선택해서, Refactor > Extract > Function 을 이용해서 함수로 만든다. 함수 이름은 bind() 로 하자.
- 이제 함수 시그니쳐의 홀더 위에 커서를 놓고 Alt(Option) + Enter 를 눌러서 Convert parameter to receiver 를 선택한다.
- bind() 함수를 ViewHolder 안으로 옮긴다.
- bind() 를 public 으로 바꾼다.
- bind() 를 ViewHolder 안으로 옮겼기 때문에 ViewHolder를 앞에 적어줄 필요는 없다.
onCreateViewHolder() 리팩토링
onCreateViewHolder() 메소드는 어댑터에 있고, 이 코드는 뷰 홀더를 레이아웃 리소스에서 인플레이트해주는 역할을 한다. 하지만 이건 어댑터와는 전혀 상관없고 모두 ViewHolder를 통해서 이루어진다. 그러니 뷰 홀더로 코드를 옮겨줘야 한다.
- onCreateViewHolder의 모든 코드를 선택한다.
- Refactor > Extract > Function. 함수 이름은 from으로 하자.
- from 함수 위에 커서를 놓고 Alt(Option) + Enter 를 누른다.
- Move to companion object 를 선택하자. companion object 로 옮겨서 VH 인스턴스가 아니라 VH 클래스에서 호출되게 만들어야 한다.
- 만들어진 companion object 를 ViewHolder 클래스로 옮긴다.
- from() 함수를 public 으로 바꾼다.
- onCreateViewHolder() 메소드에서 return 부분을 ViewHolder.from(parent) 로 바꾼다.
- 이제 뷰 홀더 클래스 생성자를 private 으로 바꿔주자. 어차피 from() 을 통해서 새로운 인스턴스가 만들어진다.