코틀린 기반으로 쓰여짐
리사이클러뷰를 완벽 이해하려고 써보는 리사이클러뷰 포스팅
물론 틀린점 있을거다. 적극 피드백 환영
https://developer.android.com/jetpack/androidx/releases/recyclerview?hl=ko
RecyclerView | Android 개발자 | Android Developers
RecyclerView 메모리 사용량을 최소화하면서 UI에 많은 양의 데이터를 표시합니다. 이 표에는 androidx.recyclerview 그룹의 모든 아티팩트가 나열되어 있습니다. 이 라이브러리는 2022년 6월 29일에 최종 업
developer.android.com
리사이클러뷰란?
출처 - 안드로이드 디밸로퍼
그렇다. 리사이클러뷰란 메모리 사용량을 최소화 하면서 많은 양의 데이터를 표시하기 위한 도구이다.
그 전에 많이 쓰이던 리스트 뷰는 새로운 데이터가 필요할 때마다 기존에 있던 데이터는 삭제하고 새로운 데이터를 만드는 형식이였는데
리사이클러뷰는 기존에 있던 데이터를 재 활용해서 데이터의 낭비를 최소화 하는데 중점을 두었다.
아래 그림이 굉장히 잘 설명했다고 생각한다.
또 오늘 만들어볼 것은 뷰바인딩을 이용한다. 고로 뷰 바인딩은 기본적으로 알고 있어야 한다!
고로 모른다면 가서 게시글 한번 보고 오기를 추천한다.
https://todaycode.tistory.com/29
안드로이드 뷰 바인딩(view binding)
1. 뷰 바인딩 1-1. 라떼는 말이야... 1-2. 변천사 1-3. findViewById와의 차이점 2. 사용법 2-1. gradle 추가 2-2. 액티비티 2-3. 프래그먼트 2-4. viewBindingIgnore 1. 뷰 바인딩 1-1. 라떼는 말..
todaycode.tistory.com
https://velog.io/@5y145/RecyclerView
각설하고 바로 만들어 보겠다.
1)
틀을 만들어준다.
<?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/todo_list"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/clear_btn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:itemCount="3" //미리볼 갯수!
tools:listitem="@layout/item_todo"> //이렇게 하면 아이템 리스트들의 미리보기를 지원한다.
</androidx.recyclerview.widget.RecyclerView>
<Button
android:id="@+id/clear_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="clear all"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/todo_list"
app:layout_constraintStart_toStartOf="parent">
</Button>
</androidx.constraintlayout.widget.ConstraintLayout>
2. 리사이클러뷰들의 아이템을 구성한다
<?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="100dp">
<ImageView
android:src="@drawable/ic_launcher_background"
android:id="@+id/image_IV"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/todo_title_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</ImageView>
<TextView
android:id="@+id/todo_title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/completed_check_box"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="do something">
</TextView>
<CheckBox
android:id="@+id/completed_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
</CheckBox>
</androidx.constraintlayout.widget.ConstraintLayout>
3. 데이터 클래스를 만들어준다.
Todo.kt
package com.example.todolist
data class Todo(
val title : String,
var completed : Boolean,
)
4. 어댑터를 만들어준다
package com.example.todolist
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.todolist.databinding.ItemTodoBinding
class TodoAdapter(private val todos:List<Todo>):RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
fun clearAll() {
todos.forEach {
it.completed=true
}
notifyDataSetChanged() //데이터 변경 됐으니까다시 호출해!
}
// 호출되는 횟수가 정해짐
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
Log.d("TAG","onCreateViewHolder")
val binding = (ItemTodoBinding.inflate(LayoutInflater.from(parent.context),parent,false))
return TodoViewHolder(binding).also {
binding.completedCheckBox.setOnCheckedChangeListener { compoundButton, b ->
Log.d("TAG","isChecked")
todos.getOrNull(it.adapterPosition)?.completed = b
}
}
}
// 스크롤을 할때 호출됨.
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
Log.d("TAG","onBindViewHolder $position")
holder.bind(todos[position])
}
override fun getItemCount(): Int= todos.size //아이템의 크기
class TodoViewHolder(private val binding:ItemTodoBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(todo:Todo) {
binding.todoTitleText.text = todo.title
// 재활용되는지 확인해보자.
binding.completedCheckBox.isChecked = todo.completed
}
}
}
여기서 중요 포인트가 하나 있다.
onCreateViewHolder 에서
val binding = (ItemTodoBinding.inflate(LayoutInflater.from(parent.context),parent,false))
여기서 첫번째 파라미터로 context를 받아와야하는데 context는 주어지지 않는다.
그래서 간혹 Adapter에
class TodoAdapter(private val todos:List<Todo>,Context context) 이런식으로 주는 경우가 있는데
그럴 필요 없을 뿐더러 그러면 안된다.
Viewgroup은 view를 상속받았고 이미 context를 가지고 있다.
parent에 이미 context가 있음을 명심하자!
5. 연결해주기
MainAcitivty.kt
package com.example.todolist
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.todolist.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
private val todos = listOf(
Todo("list1",false),
Todo("list2",false),
Todo("list3",false),
Todo("list4",false),
Todo("list5",false),
Todo("list6",false),
Todo("list7",false),
Todo("list8",false),
Todo("list9",false),
Todo("list10",false),
Todo("list11",false),
Todo("list12",false),
Todo("list13",false),
Todo("list14",false),
Todo("list15",false),
Todo("list16",false),
Todo("list17",false),
Todo("list18",false),
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initializeViews()
}
private fun initializeViews() {
binding.todoList.layoutManager = LinearLayoutManager(this)
binding.todoList.adapter = TodoAdapter(todos)
binding.clearBtn.setOnClickListener{
(binding.todoList.adapter as TodoAdapter)?.clearAll()
}
}
}
실제로 이렇게 하드코딩하는 경우는 없겠지만 데이터베이스에서 가져오는건 나중에 따로 다루도록 하겠다!
6. 결과
하나 주목해서 봐야할껀 로그캣이다!
2022-08-22 21:36:35.663 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:35.688 9309-9309/com.example.todolist D/TAG: onBindViewHolder 0
2022-08-22 21:36:35.690 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:35.693 9309-9309/com.example.todolist D/TAG: onBindViewHolder 1
2022-08-22 21:36:35.696 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:35.699 9309-9309/com.example.todolist D/TAG: onBindViewHolder 2
2022-08-22 21:36:35.701 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:35.704 9309-9309/com.example.todolist D/TAG: onBindViewHolder 3
2022-08-22 21:36:35.706 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:35.710 9309-9309/com.example.todolist D/TAG: onBindViewHolder 4
2022-08-22 21:36:37.316 9309-9309/com.example.todolist D/TAG: isChecked
2022-08-22 21:36:38.215 9309-9309/com.example.todolist D/TAG: isChecked
2022-08-22 21:36:38.981 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:38.990 9309-9309/com.example.todolist D/TAG: onBindViewHolder 5
2022-08-22 21:36:39.163 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:39.169 9309-9309/com.example.todolist D/TAG: onBindViewHolder 6
2022-08-22 21:36:39.400 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:39.405 9309-9309/com.example.todolist D/TAG: onBindViewHolder 7
2022-08-22 21:36:40.201 9309-9309/com.example.todolist D/TAG: onCreateViewHolder
2022-08-22 21:36:40.206 9309-9309/com.example.todolist D/TAG: onBindViewHolder 8
2022-08-22 21:36:40.336 9309-9309/com.example.todolist D/TAG: onBindViewHolder 9
2022-08-22 21:36:40.338 9309-9309/com.example.todolist D/TAG: isChecked
2022-08-22 21:36:40.532 9309-9309/com.example.todolist D/TAG: onBindViewHolder 10
2022-08-22 21:36:40.535 9309-9309/com.example.todolist D/TAG: isChecked
2022-08-22 21:36:41.290 9309-9309/com.example.todolist D/TAG: onBindViewHolder 11
2022-08-22 21:36:41.370 9309-9309/com.example.todolist D/TAG: onBindViewHolder 12
2022-08-22 21:36:41.534 9309-9309/com.example.todolist D/TAG: onBindViewHolder 13
2022-08-22 21:36:42.335 9309-9309/com.example.todolist D/TAG: onBindViewHolder 14
2022-08-22 21:36:42.398 9309-9309/com.example.todolist D/TAG: onBindViewHolder 15
2022-08-22 21:36:42.499 9309-9309/com.example.todolist D/TAG: onBindViewHolder 16
2022-08-22 21:36:43.197 9309-9309/com.example.todolist D/TAG: onBindViewHolder 17
2022-08-22 21:36:45.398 9309-9309/com.example.todolist D/TAG: isChecked
2022-08-22 21:36:45.998 9309-9309/com.example.todolist D/TAG: isChecked
oncreateViewHolder가 일정 데이터가 지난후에는 더 이상 소환되지 않는다
왜? 재활용하기 때문에 더이상 create할 필요는 없어서이다.
참고
https://www.youtube.com/watch?v=RYM2H0Qzq9I
VIDEO