본문 바로가기
Android

BaseRecyclerView (리사이클러 뷰)

by Jiwon_Loopy 2024. 7. 26.
반응형

이론


리사이클러 뷰의 장점

  • 성능 개선: 리사이클러뷰는 스크롤 시 재사용 가능한 뷰를 효율적으로 관리하여 성능을 향상시킵니다. 사용자가 스크롤할 때 불필요한 뷰 생성을 줄이고, 이미 생성된 뷰를 재사용함으로써 메모리 사용을 최적화하고 더 빠른 로딩 시간을 제공합니다.
  • 레이아웃 유연성: 리사이클러뷰는 LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager 등 다양한 레이아웃 매니저를 지원하여, 목록을 세로, 가로, 격자형태 등 다양하게 표시할 수 있습니다.
  • 애니메이션과 데코레이션 지원: 기본적으로 제공하는 애니메이션 효과들과 아이템 데코레이션 기능을 통해, 목록에 간격을 주거나 구분선을 추가하는 등의 시각적인 개선을 손쉽게 적용할 수 있습니다.
  • 확장성: 사용자 정의 뷰홀더와 어댑터 패턴을 사용하여, 각 항목의 레이아웃을 다양하게 구성할 수 있습니다. 이를 통해 다양한 데이터 유형과 복잡한 레이아웃을 효율적으로 처리할 수 있습니다.
  • 다양한 이벤트 처리: 아이템 클릭, 롱 클릭, 드래그 앤 드롭, 스와이프 제스처 등 다양한 인터랙션을 손쉽게 구현할 수 있습니다.

 

 

 

리스트 뷰와 다른 점

기능 리사이클러 뷰  리스트 뷰
뷰 재사용과 성능 뷰홀더 패턴을 통한 고성능 뷰 재사용 뷰 재사용 가능하지만 뷰홀더 패턴이 없으면 비효율적
레이아웃 관리 다양한 레이아웃 매니저 지원 주로 세로 리스트, 격자형은 GridView 필요
애니메이션과 데코레이션 애니메이션 내장, 아이템 데코레이션 지원 기본 애니메이션 없음, 구분선 지원
인터랙션 처리 다양한 상호작용(드래그, 스와이프 등) 지원 기본 클릭과 롱 클릭 지원만 가능

 

DiffUtil

DiffUtil은 두 리스트 간의 차이점을 계산하는 유틸리티 클래스입니다. 이 클래스는 새 데이터와 기존 데이터 사이의 차이를 계산하고, 이 정보를 바탕으로 리사이클러뷰에 효율적인 업데이트(예: 추가, 삭제, 변경)를 수행할 수 있도록 도와줍니다. DiffUtil은 특히 데이터 변경이 복잡하거나 데이터셋이 큰 경우에 유용하며, UI 스레드의 작업을 최소화하여 더 부드러운 사용자 경험을 제공합니다.

 

실습


BaseAdapter.kt (베이스 어댑터)

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView

abstract class BaseAdapter<T : Any, VB : ViewDataBinding>(
    diffCallback: BaseDiffCallback<T>
) : ListAdapter<T, BaseAdapter.BaseViewHolder<VB>>(diffCallback) {

    abstract val layoutId: Int

    abstract fun bind(binding: VB, item: T)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<VB> {
        val binding: VB = DataBindingUtil.inflate(
            LayoutInflater.from(parent.context),
            layoutId, parent, false
        )
        return BaseViewHolder(binding)
    }

    override fun onBindViewHolder(holder: BaseViewHolder<VB>, position: Int) {
        bind(holder.binding, getItem(position))
        holder.binding.executePendingBindings()
    }

    class BaseViewHolder<VB : ViewDataBinding>(val binding: VB) : RecyclerView.ViewHolder(binding.root)
}

 

 

BaseDiffUtilCallback.kt (베이스 DiffUtil)

package com.example.avocado_android.base

import androidx.recyclerview.widget.DiffUtil

class BaseDiffCallback<T : Any>(
    private val itemsTheSame: (oldItem: T, newItem: T) -> Boolean,
    private val contentsTheSame: (oldItem: T, newItem: T) -> Boolean
) : DiffUtil.ItemCallback<T>() {
    override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
        return itemsTheSame(oldItem, newItem)
    }

    override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
        return contentsTheSame(oldItem, newItem)
    }
}

 

 

구현 예시

import com.example.avocado_android.R
import com.example.avocado_android.base.BaseAdapter
import com.example.avocado_android.base.BaseDiffCallback
import com.example.avocado_android.databinding.ItemHomeBestSearchBinding
import com.example.avocado_android.databinding.ItemLibraryWordCardBinding
import com.example.avocado_android.domain.model.response.library.LibraryWordDto

//어댑터의 항목은 아이템 클래스와, 바인딩을 가저옴.
class LibraryCardAdapter : BaseAdapter<LibraryWordDto, ItemLibraryWordCardBinding>(
    BaseDiffCallback(
        itemsTheSame = { oldItem, newItem -> oldItem == newItem },
        contentsTheSame = { oldItem, newItem -> oldItem == newItem }
        // 속성 요소, 혹은 속성 자체를 비교
    )
) {

    override val layoutId: Int
        get() = R.layout.item_library_word_card
        // 리사이클러뷰 안에 들어갈 아이템 XML을 id로 가저옴.

    override fun bind(binding: ItemLibraryWordCardBinding, item: LibraryWordDto) {
        binding.libraryData = item
        //데이터 바인딩 항목과 아이템을 묶어줌
    }
}

 

 

연결 예시

private lateinit var libraryAdapter: LibraryCardAdapter

private fun initAdapter() {
        libraryViewModel = ViewModelProvider(this)[LibraryViewModel::class.java]
        libraryAdapter = LibraryCardAdapter()
		//어댑터 생성
        with(binding) {
            libraryWordCardRv.adapter = libraryAdapter
            libraryWordCardRv.addItemDecoration(GridSpacingItemDecoration(spanCount = 2, 16f.fromDpToPx()))
        }
        //어댑터 연결
    }
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED){
        libraryViewModel.wordCardData.collectLatest {response ->
            libraryAdapter.submitList(response.libraryWordDtoList)
            Glide.with(this@LibraryFragment)
                .load(response.characterImgUrl)
                .into(binding.libraryLogoImageIv)
        }
    }
}
//서버에서 온 값을 submitList를 이용하여 리스트를 넣어줌
728x90
반응형

'Android' 카테고리의 다른 글

Wear Os (워치)  (4) 2024.09.17
PCM (펄스 코드 변조)  (5) 2024.09.09
WebRTC (1) - 웹RTC (스트리밍)  (1) 2024.09.08
Glide 글라이드 (이미지)  (2) 2024.09.07
안드로이드 포스팅 시작  (0) 2024.07.26