앱에서 RecyclerView 사용하기

이번 포스팅에서는 Recyclerview를 사용하는 법에 대해 알아보도록 하겠습니다.

# Recyclerview의 특징

Recyclerview는 화면에 리스트 형식의 데이터를 표시하기 위해서 사용하는 모듈입니다. 보통 화면에 리스트뷰를 표시할수 있게 하는 ListView는 예를들어 데이터가 10개 있을 경우 데이터를 표시하기 위한 ViewHolder가 10개 필요합니다. 그러나 Recyclerview는 ViewHolder를 6개만 만들고 화면에는 5개를 표시한 후 화면 바깥으로 1번 ViewHolder가 빠져나가면 7번 ViewHolder로 변경해서 재사용합니다. 그래서 자원을 더 아낄 수 있게 되는 것이죠.

또 데이터는 Recyclerview Adapter를 통해 ViewHolder에 들어가게 되는데 ViewHolder에 데이터 1을 넣어서 표현했을 경우, ViewHolder는 그대로 놔두고 데이터 2를 넣는 식으로 ViewHolder를 재활용해서 사용할 수 있습니다. 그래서 Recyclerview라는 이름이 붙게 된 것이죠.

# Recyclerview 구현

# 라이브러리 추가

우선은 Recyclerview를 사용하기 위한 라이브러리를 추가합니다.

1
2
3
dependencies {
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
}

# 화면 구성

다음은 화면에 Recyclerview 모듈을 추가합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

# ViewHolder 화면구성

다음으로 ViewHolder의 화면을 구성합니다. ViewHolder는 LinearLayoutTextView 2개를 쌓은 단순한 구조로 정의했습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Main TextView"
        android:textSize="24dp"
        android:padding="5dp" />

    <TextView
        android:id="@+id/tv_sub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Sub TextView"
        android:textSize="18dp"
        android:padding="5dp" />

</LinearLayout>

# Recyclerview 어댑터 작성

다음은 RecyclerView.Adapter 클래스를 상속받는 Recyclerview Adapter를 작성합니다. 외부에서 전달받을 데이터는 dataSet이라고 정의했습니다.

그리고 ViewHolder 클래스를 작성합니다. 여기서는 외부에서 전달받은 데이터를 ViewHolder 화면의 텍스트뷰와 연결하는 작업을 bind함수로 정의합니다.

onCreateViewHolder에서 ViewHolder클래스에 list_item으로 inflate한 객체를 넘겨준 ViewHolder를 작성하여 반환합니다. onBindViewHolder에서는 ViewHolder 클래스의 bind함수로 작성된 ViewHolder와 전달받은 개별 데이터를 연결합니다. getItemCount에서는 전달받은 데이터의 전체길이를 넘겨주어 어댑터가 ViewHolder를 얼마나 만들어야 할지를 결정하게 합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class RecyclerViewAdapter(private val dataSet: ArrayList<List<String>>): RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {
    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(dataSet[position])
    }

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

    class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
        private val tvMain: TextView = view.tv_main
        private val tvSub: TextView = view.tv_sub

        fun bind(data:List<String>) {
            tvMain.text = data[0]
            tvSub.text = data[1]
        }
    }
}

# 데이터셋 준비

다음으로 메인액티비티에서 Recyclerview로 넘겨줄 데이터셋을 만듭니다. String을 두개 포함한 배열을 100개 가지는 리스트의 리스트 형식으로 작성하였습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class MainActivity : AppCompatActivity() {
    private val dataSet: ArrayList<List<String>> = arrayListOf()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        addData()
    }

    private fun addData() {
        for (i in 0..99) {
            dataSet.add(listOf("$i th main", "$i th sub"))
        }
    }
}

# Recyclerview와 Adapter 연결

마지막으로 Recyclerview와 Adapter를 연결해줍니다. Recyclerview 안에서 ViewHolder를 어떻게 정렬할지 결정하는 LayoutManager 프로퍼티를 정의하는데 여기서는 LinearLayoutManager를 사용하였습니다. 그 외로 GridLayoutManagerStaggeredGridLayoutManager를 사용할 수도 있습니다.

그리고 위에서 만들어 준 RecyclerViewAdapter를 초기화하여 adapter 프로퍼티에 반영해줍니다.

addItemDecoration 속성에 DividerItemDecoration.HORIZONTAL을 전달하면 각 ViewHolder 사이에 구분선을 표시할 수도 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MainActivity : AppCompatActivity() {
    private val dataSet: ArrayList<List<String>> = arrayListOf()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        addData()

        recycler_view.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
//        recycler_view.layoutManager = GridLayoutManager(this, 2)

        recycler_view.adapter = RecyclerViewAdapter(dataSet)
        recycler_view.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL))
    }

    private fun addData() {
        for (i in 0..99) {
            dataSet.add(listOf("$i th main", "$i th sub"))
        }
    }
}

이렇게 해서 Recyclerview를 사용하는 법에 대해 알아보았습니다.

Built with Hugo
Theme Stack designed by Jimmy