[Android] RecyclerView, Base Class 만들기

Hanbin·2021년 8월 25일
1

Android

목록 보기
2/6
post-thumbnail

💡 RecyclerView 만들기

list를 보여주는 화면을 구현할 때 매번 사용하는 RecyclerView. 좀 더 편하게 사용하기 위해 반복되는 코드를 줄여보자!

먼저 BaseClass 없이 구현되는 RecyclerViewviewBinding을 이용해서 만들어 보자.

item_simple.xml

ViewHolder 에서 사용할 레이아웃을 만들어준다.

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

    <TextView
        android:id="@+id/tv_position"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center"
        android:paddingHorizontal="20dp"
        tools:text="1" />

    <TextView
        android:id="@+id/tv_simple"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:paddingVertical="10dp"
        tools:text="테스트" />
</LinearLayout>

RecyclerView.ViewHolder

각 아이템 역할을 하는 ViewHolder를 먼저 만들어준다.

생성자에서 itemView를 설정 해주고 viewBinding에 해당 itemView를 넣어줬다.

init 블록에서 클릭 이벤트를 설정해 주었다.

onBindView()에선 데이터를 받고 포지션과 전달받은 데이터를 설정해 주었다.

RecyclerView.Adapter

ViewHolder 생성 및 관리하는 Adapter를 만들어준다. onCreateViewHolder(), onBindViewHolder(), getItemCount() 이 세 가지 함수는 필수로 구현해 줘야 한다.

  • onCreateViewHolder() : ViewHolder를 새로 만들어야 할 때 호출된다.
  • onBindViewHolder() : ViewHolder를 데이터와 연결할 때 호출된다. 이를 통해 ViewHolder의 레이아웃에 데이터를 채워준다.
  • getItemCount() : list의 크기를 가져올 때 호출되며, list의 총 크기를 설정해준다.
  • getItemViewType() : ViewHolder의 레이아웃을 정해준다.

activity_main.xml

XML에 RecyclerView를 선언하고 layoutManager와 orientation을 설정해 주었다.

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_view_binding"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

Activity

RecyclerView에 만들어 놓은 Adpater를 설정해 주면 된다.

val simpleAdapter = SimpleAdapter {
    Toast.makeText(this, "Click $it", Toast.LENGTH_SHORT).show()
}
viewBinding.rvViewBinding.adapter = simpleAdapter
simpleAdapter.replaceAll(arrayListOf("가", "나", "다", "라", "마", "바"))

🧪 Base 만들기

이제 BaseClass를 이용해 RecyclerView를 만들어보자. (XML, Activity 설정은 생략)

BaseViewHolder

어떤 데이터, ViewBinding을 받을지 몰라 Generic 타입으로 정의해주었다.

생성자로 parentlayourRes를 받아 itemView를 설정해 주었다.

ViewHolder의 레이아웃에 데이터를 채우기 위해 필요한 부분을 추상 메소드, 프로퍼티로 만들어 주었다.

  • viewBinding : ViewHolder의 레이아웃에 데이터를 세팅하기 위함.
  • onBindView() : AdapteronBindViewHolder()가 호출되었을 때 데이터를 받고 처리하기 위함.

BaseAdapter

ViewHolder와 동일하게 Generic 타입을 정의해주었고 파라미터로 layoutRes를 받는다.

추상 메소드 두 가지를 추가해 준다.

  • onCreateViewBinding() : ViewHolder에 필요한 ViewBinding을 생성하기 위함.
  • onBindView() : ViewHolderbindView 호출을 위함.

이제 override한 함수를 살펴보자.

onCreateViewHolder

추상 클래스인 BaseViewHolder를 생성해 준다. 그 과정에서 추상 프로퍼티, 메소드를 구현해야 하며 BaseApdater의 추상 메소드를 설정해 주었다.

onBindViewHolder

BaseViewHolder의 추상 메소드 onBindView()를 호출한다.

구현하기

이제 추상 메소드 두 가지를 구현하는 작업을 진행하면 된다.

onCreateViewBinding() : ViewHolder가 생성될 때 호출될 것이고 ViewBinding을 생성해 준다.

onBindView() : AdpateronBindViewHolder()가 호출될 때 동작할 것이며 레이아웃에 데이터를 설정해 준다.

Base를 이용함으로써 구현해야 할 코드가 현저히 줄어든 것을 확인할 수 있었지만, 고민거리 하나가 생겼다.

notify가 일어났을 때와 overScroll로 인해 ViewHolder가 재사용 되면서 해당 데이터의 변경이 일어날 때 AdapteronBindViewHolder()가 호출되는데 현재 구현한 onBindView()가 계속해서 호출되는 것이다.

onBindView() 구현부를 살펴보면 해당 뷰의 클릭이벤트를 설정해 주고 있고, 위에 했던 SimpleViewHolder에서는 init 블락에서 설정해 주고 있다. onBindView()는 계속해서 호출될 가능성이 높기 때문에 최초 init 블록에서 설정해 줘야 한다.

하지만 구현한 AdapterViewHolder를 들고 있지 않고 Base에서 생성하기 때문에 init 블록에서 클릭 이벤트를 설정할 경우 데이터 변경이나 adapterPosition 변경을 대응하지 못한다.

고민 끝에 AdapterViewHolder 생성을 Base에서 제거하기로 했다.

🔨 Base 수정하기

기존 BaseViewHolder는 동일하고 BaseAdapter만 수정을 진행해 준다.

BaseAdapter

기존 추상 메소드와 onCreateViewHolder() 메소드를 제거해 준다.

구현하기

BaseViewHolder를 구현한 클래스와 AdapteronCreateViewHolder() 메소드를 구현해 준다.

ViewHolder

추상 프로퍼티와 메소드를 구현해 주고 init 블록에 클릭 이벤트를 등록해 준다.

Adapter

위에서 만든 ViewHolder 클래스를 이용해 onCreateViewHolder() 메소드를 구현해 준다.

🙏 마치며

다양한 방법을 시도하고 고민한 끝에 Base 클래스를 만들 수 있었다. 추후 개발을 진행하면서 더 개선할 수 있는 방안을 찾아봐야겠다. 해당 샘플은 깃헙 레파지토리에서 확인해 볼 수 있다.

1개의 댓글

comment-user-thumbnail
2023년 9월 21일

좋은 글 감사합니다~

답글 달기