1. Diffutil 그리고 ListAdapter
어제는 RecyclaearView와 item layout을 연결하는데 있어서 Recyclearview를 사용해서 연결하였다.
하지만, 해당 방식은 삭제와 삽입의 유지보수가 힘들다는 단점이 있다.
그리고 놀랍게도 안드로이드 스튜디오는 이미 그 단점을 보완한 형태를 가지고있는데 그게 바로
'ListAdapter'이다.
class Adapter : ListAdapter<Item, ViewHolder>(diffUtilCallback)
Listadapter의 기본 형태로, 여기서 새로운 개념 diffutil이 등장한다.
그렇다면 Diffutil은 뭘까?
1)Diffutil
Diffutil은 이전 데이터(oldItem)와 현재 데이터(newItem)간의 상태 차이를 계산하고, 반드시 업데이트해야 할 최소한의 데이터에 대한 것만 갱신이 된다. 즉 데이터 업데이트 횟수를 최소한으로 가져간다.
이 것이 왜 혁신적이냐?
이전에는 사람들이 사용했단 간소한 방법인 notifyDataSetChanged()는 사용하기는 편하지만, 리스트를 전부 지운 뒤 객체를 처음부터 새로 만드는 동작 방식을 진행한다. 즉 성능적인 영향에서 치명적인 악형향을 미치게 된다는 것 이다.
Diffutil의 형태는
getOldListSize() | 이전(원래) 목록의 크기를 반환한다. 굳이 제어할 필요는 없다. |
getNewListSize() | 새로 들어온 목록의 크기를 반환한다. 굳이 제어할 필요는 없다 |
areItemsTheSame (int oldItemPosition , int newItemPosition) |
두 아이템이 같은 객체인지 여부를 판단한다 |
areContentsTheSame (int oldItemPosition , int newItemPosition) |
두 아이템이 같은 데이터를 갖고 있는지 여부를 반환한다. 앞의 areItemsTheSame이 true일 때만 호출된다. 만약 두 객체가 다르다면, 비교할 이유가 없기 때문이다. |
getChangePayload (int oldItemPosition , int newItemPosition) |
areItemsTheSame : true areContentsTheSame : false 라면 새로운 녀석이 들어왔다고 간주하고 해당 메소드가 호출되어 변경된 내용에 대한 페이로드를 가져온다. 다른 메소드들은 public abstract이지만 해당 메소드는 public @nullable object이다. 따라서 override할 필요는 없다. 하지만 이 메소드도 굳이 제어할 필요는 없다. |
class BookMarkDiffutilCallBack : DiffUtil.ItemCallback<Bookmarkitem>() {
override fun areItemsTheSame(oldItem: Bookmarkitem, newItem: Bookmarkitem): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Bookmarkitem, newItem: Bookmarkitem): Boolean {
return oldItem == newItem
}
}
따라서 내가 지정해준 diffutil에서는 각 아이템 객체의 동일 여부와 두 아이템이 서로 다른 데이터를 가지고 있는 것만 지정해준다.
ListAdapter는 RecyclearView의 서브 클래스이기 때문에 두 아이템의 사이즈를 넣을 필요가 없다.
하지만 용도에 따라서 이 두 가지도 사용될 수 있다.
하지만 보편적으로는 사용되지 않으므로 없다고 봐도 무방하며, 나중에 개발에 있어서 확장적으로 사용할 일이 있다면 이러한 것들이 있다는 것을 인지하는 것이 좋다.
2)ListAdapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter // 이 부분이 있어야 override할 수 있음
import androidx.recyclerview.widget.RecyclerView
class BookMarkAdapter :
ListAdapter<Bookmarkitem, BookMarkAdapter.BookMarkViewHolder>(BookMarkDiffutilCallBack())
{
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookMarkViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.item_book_mark, parent, false)
return BookMarkViewHolder(view)
}
override fun onBindViewHolder(holder: BookMarkViewHolder, position: Int) {
holder.bind(getItem(position))
}
class BookMarkViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val bookMarkTextView: TextView = itemView.findViewById(R.id.bookmark_textitem)
fun bind(item : Bookmarkitem){
bookMarkTextView.text = item.bookmark
}
}
class BookMarkDiffutilCallBack : DiffUtil.ItemCallback<Bookmarkitem>() {
override fun areItemsTheSame(oldItem: Bookmarkitem, newItem: Bookmarkitem): Boolean
{
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Bookmarkitem, newItem: Bookmarkitem): Boolean
{
return oldItem == newItem
}
}
}
이전 recycleviewadapter와 다른 점이 있다면, diffutil의 추가 정도일 것이다.
또한 fun bind함수는 이전 recyclearview에서도 똑같이 적용되는 부분으로, 좀 더 데이터 관리를 깔끔하게 하기 위해서 만들어진 함수이다.
2. 튜터님의 피드백
Adapter에서
class TodoAdapter(val todoList: ArrayList<Todoitem>) :
//listApater 에 대한 공부 및 변경시도하기
RecyclerView.Adapter<TodoAdapter.TodoHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoAdapter.TodoHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_todo, parent, false)
return TodoHolder(view)
}
override fun onBindViewHolder(holder: TodoAdapter.TodoHolder, position: Int) {
holder.todo.text = todoList[position].todo
}
override fun getItemCount(): Int {
return todoList.count()
}
class TodoHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
// Holder는 재사용 하는 경우가 크게 없음. apater안에서 관리하는게 편함
// inner class는 메모리적인 이슈가 있음
// 사용 지양하는 것이 좋음
// 굳이 innder class를 뺄 필요가 없음. 내부적으로 메모리에 담겨져 있기 때문에
val todo = itemView.findViewById<TextView>(R.id.texttodo)
}
}
Fragment에서
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//여기서 뷰가 그려짐. 여기서 작업이 됨
super.onViewCreated(view, savedInstanceState)
arguments.getString() // 이 시점에서 binding해야 변수를 사용 가능
}
참고 블로그
[Android] DiffUtil 사용법 알아보기
notifyDataSetChanged() 탈출은 지능순 (우끼끼)
velog.io
https://jminie.tistory.com/146
안드로이드 [Kotlin] - RecyclerView에서 ListAdapter와 DiffUtil 사용기
ListAdapter와 DiffUtil에 대해 알아보기 전에 우선 RecyclerView와 LiveData에 대해 알아봐야 한다. 따라서 전에 작성한 포스팅을 첨부한다. https://jminie.tistory.com/144?category=1040997 안드로이드 [Kotlin] - RecyclerVi
jminie.tistory.com
https://bb-library.tistory.com/257
[안드로이드] ListAdapter의 작동 원리 및 갱신이 안되는 경우
개요 RecyclerView를 활용하여 목록을 리스팅할 때 흔히 사용하는 어답터로 RecyclerView.Adapter와 ListAdapter로 나뉜다. 전자는 아이템 목록을 직접 관리하며 값이 변경될 경우 변경된 범위, 항목에 대해
bb-library.tistory.com
https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil
'개발노트 > Kotlin' 카테고리의 다른 글
6주차 3일 다이얼로그 (0) | 2023.08.16 |
---|---|
6주차 1일 팀프로젝트 시작 (1) | 2023.08.14 |
5주차 3일 TapLayout과 Viewpager2,RecyclearView (0) | 2023.08.09 |
5주차 2일 액티비티 생명주기 (0) | 2023.08.08 |
5주차 1일 셀렉터 (0) | 2023.08.07 |