이번 포스팅에서는 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는 LinearLayout 에 TextView 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 를 사용하였습니다. 그 외로 GridLayoutManager 나 StaggeredGridLayoutManager 를 사용할 수도 있습니다.
그리고 위에서 만들어 준 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를 사용하는 법에 대해 알아보았습니다.
VIDEO