LinearLayout이나 ConstraintLayout은 그래도 개념적으로 어려운 건 없었는데
RecyclerView는... 한번 정리할 필요를 느껴서 구현하면서 내용을 적어봤다.

Recycle이라는 단어에서 알 수 있듯 view를 재사용하는 레이아웃
예를 들어, ListView로 게시글 목록 10,000개를 띄우려면 10,000개의 뷰를 만들어야 된다는 건데... 뷰 띄우는데 한참 걸릴 것이 분명하다.
반면 리사이클러뷰는 화면에 보일 만큼의 뷰를 만든다. ex) 10개
그리고 사용자가 화면을 스크롤하면 화면 위로 올라가서 더 이상 보이지 않게 되는 뷰들을 다시 갖다 쓴다.
따라서 view 를 재사용한다의 의미는 view를 새로 생성하지 않고, 기존에 사용했던 view의 데이터만 바꿔서 다시 사용한다는 뜻이라고 보면 된다.
중요한건 viewHolder를 통해 view를 관리 및 재사용하고 view 안의 데이터만 리셋한다는 것!
그렇다면 어떻게 그게 가능한건데? 라는 물음이 자연스럽게 떠오른다.
바로 adapter와 viewHolder가 있기에 가능한 것!
아래에서 그 두 가지에 대해 더 자세히 알아보도록 하자.
어댑터, 뷰홀더를 갖는다.
Adapter는 데이터 리스트를 관리하여 포지션에 맞게 viewHolder의 view와 연결하여 표시하는 역할.
RecyclerView.Adapter는 추상 클래스이다. 따라서 메서드 오버라이딩이 강제된다.
오버라이딩 해야하는 메서드는 3개다.
onCreateViewHolder()
getItemCount()
onBindViewHolder()
ViewHolders는 RecyclerView의 각 항목을 나타내는 View의 틀이라고 보면 된다.
각 항목의 View를 보유하고 관리하는 역할을 한다.
각 항목의 레이아웃 및 동작을 정의하는 데에 사용한다.
어떤 친구인지 대충 느낌이 왔다면 이제 구현해보자
내가 구현한 순서는 이렇다.
buildFeatures {
viewBinding = true
}
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
}
<?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="match_parent"
android:orientation="vertical"
android:padding="30dp">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="제목" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="내용" />
</LinearLayout>
리사이클러뷰 어댑터와 뷰홀더 구현 부분의 전체 코드는 이렇다.
// 리사이클러뷰 어댑터 구현
inner class Adapter: RecyclerView.Adapter<Adapter.ViewHolder>(){
// 리사이클러뷰 뷰홀더 구현
inner class ViewHolder(rowBinding: RowBinding):RecyclerView.ViewHolder(rowBinding.root){
var rowBinding:RowBinding
init {
this.rowBinding = rowBinding
// 레이아웃 구성
this.rowBinding.root.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// row.xml 뷰바인딩
val rowBinding = RowBinding.inflate(layoutInflater)
// 뷰홀더 객체 생성
val viewHolder = ViewHolder(rowBinding)
return viewHolder
}
override fun getItemCount(): Int {
// 생성할 항목의 수
return 40
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// 뷰홀더에 엮을 내용
holder.rowBinding.textView.text = "게시글 ${position}"
holder.rowBinding.textView2.text = "게시글 내용은 별거 없습니다"
}
}
조금씩 떼어서 볼까!
inner class Adapter: RecyclerView.Adapter<Adapter.ViewHolder>()
inner class ViewHolder(rowBinding: RowBinding):RecyclerView.ViewHolder(rowBinding.root){
}
inner class ViewHolder(rowBinding: RowBinding):RecyclerView.ViewHolder(rowBinding.root){
var rowBinding:RowBinding
init {
this.rowBinding = rowBinding
// 레이아웃 구성
this.rowBinding.root.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
}
참고로 adapter는 추상클래스다. 덜 만들어진 클래스라 개발자가 원하는 목적에 맞춰 나머지를 구성해줘야 객체 생성이 가능하다는 뜻!! (따라서 메서드 오버라이딩이 강제된다)
onCreateViewHolder(), getItemCount(), onBindViewHolder()는 adapter를 구현하면 자동으로 따라오는 인터페이스이다. 어차피 구현 안해주면 이렇게 빨간 밑줄로 경고가 뜬다. 그냥 implement 해주면 된다.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// row.xml 뷰바인딩
val rowBinding = RowBinding.inflate(layoutInflater)
// 뷰홀더 객체 생성
val viewHolder = ViewHolder(rowBinding)
// 리턴
return viewHolder
}
override fun getItemCount(): Int {
// 생성할 항목의 수
return 40
}
대충 흐름을 정리하자면 이런거다
getItemCounte() 뷰홀더 40개 생성해줘
-> onCreateViewHolder() ㅇㅇ뷰홀더 40개 생성할게
-> onBindViewHolder() 생성된 뷰홀더에 데이터 연결
여기까지 하면 구현은 끝났으니 이제 만든 거 적용만 해주면 된다.
// View를 초기화하는 메서드
fun initView(){
activityMainBinding.apply {
// RecyclerView 설정
recyclerViewResult.apply {
// 어뎁터
adapter = RecyclerViewAdapter()
// 레이아웃 매니저
layoutManager = LinearLayoutManager(this@MainActivity)
// 데코레이션
val deco = MaterialDividerItemDecoration(this@MainActivity, MaterialDividerItemDecoration.VERTICAL)
addItemDecoration(deco)
}
}
}
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
initView()
}
와아 끝!
맨 위에 있던 움짤처럼
리사이클러뷰가 잘 만들어진 걸 볼 수 있다.
왜 뷰홀더 클래스를 제네릭 타입으로 하는지?
왜 inner class로 선언하는지?
매개변수에 들어간 parent는 뭔지? 등
메모장에 물음표밖에 없다 뭔 물음표 살인마도 아니고
아무튼 여기에 이거까지 다 적으면
여러 내용이 섞여 혼잡해질 것 같아서
그건 다른 게시글에 정리해서 작성해야겠다.