Seoplee
개발의 섭리, Seoplee의 개발
Seoplee
  • 분류 전체보기 (54)
    • Android (26)
      • Architecture (12)
      • Compose (0)
      • Tips (11)
      • 트러블슈팅 (3)
    • IOS (1)
      • Tips (1)
    • Kotlin (1)
    • Coroutine (3)
      • Flow (3)
    • RxJava (12)
    • CI&CD (1)
    • WEB (8)
    • Network (1)
    • ETC (1)
    • (임시) (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Seoplee

개발의 섭리, Seoplee의 개발

Android/Tips

Recyclerview adapter 재활용하기

2021. 11. 15. 21:41

Recyclerview는 정말 자주 사용하는 기능 중 하나이기 때문에, 미리 규격화하여 재활용하여 사용하는것이 좋다.

 

interface BoardListListener: AdapterListener {

    fun onClickItem(model: BoardListModel)

}

-

abstract class ModelViewHolder<M: Model>(
    binding: ViewBinding,
    protected val viewModel: BaseViewModel,
    protected val resourcesProvider: ResourcesProvider
): RecyclerView.ViewHolder(binding.root) {

    abstract fun reset()

    open fun bindData(model: M){
        reset()
    }

    abstract fun bindViews(model: M, adapterListener: AdapterListener)

}

-

class BoardViewHolder(
    private val binding:ViewholderBoardBinding,
    viewModel: BaseViewModel,
    resourcesProvider: ResourcesProvider
): ModelViewHolder<BoardListModel>(binding, viewModel, resourcesProvider) {

    override fun reset() = with(binding) {

    }

    override fun bindViews(model: BoardListModel, adapterListener: AdapterListener) = with(binding) {
        if(adapterListener is BoardListListener) {
            root.setOnClickListener {
		//todo
            }
        }
    }

    override fun bindData(model: BoardListModel)  {
        super.bindData(model)
        with(binding) {
            nameTextView.text = model.name
            titleTextView.text = model.title
        }
    }

}

 

Viewholder의 정보를 담을 추상클래스를 작성하고 상속받아 사용한다.

 

bindViews: model은 하나의 viewholder에 들어갈 정보들을 구성하는 data class를 주로 사용하고, 각 객체등의 동작(onClick등)들을 구현하는 adapterListener를 담는다.

 

bindData: 실제 layout의 위젯들과 model의 데이터를 bind한다.

 

object ModelViewHolderMapper {

    @Suppress("UNCHECKED_CAST")
    fun <M: Model> map(
        parent: ViewGroup,
        type: CellType,
        viewModel: BaseViewModel,
        resourcesProvider: ResourcesProvider
    ): ModelViewHolder<M> {
        var inflater = LayoutInflater.from(parent.context)
        val viewHolder = when (type) {
            CellType.ARTICLE_CELL -> BoardViewHolder(
                ViewholderBoardBinding.inflate(inflater, parent, false),
                viewModel,
                resourcesProvider
            )
        }
        return viewHolder as ModelViewHolder<M>
    }
}

 

recyclerview에 담을 viewholder를 사전에 정의해둔 CellType이라는 enum class를 기준으로 mapping하는 클래스

 

하나의 adpater에 담는 모델들의 CellType만을 변경해주는것만으로 편하게 viewholder를 바꿀 수 있다.

 

class ModelRecyclerAdapter<M: Model, VM: BaseViewModel>(
    private var modelList: List<Model>,
    private val viewModel: VM,
    private val resourcesProvider: ResourcesProvider,
    private val adapterListener: AdapterListener

): ListAdapter<Model, ModelViewHolder<M>>(Model.DIFF_CALLBACK) {

    override fun getItemCount(): Int = modelList.size

    override fun getItemViewType(position: Int): Int = modelList[position].type.ordinal

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ModelViewHolder<M> {
        return ModelViewHolderMapper.map(parent, CellType.values()[viewType], viewModel, resourcesProvider)
    }

    @Suppress("UNCHECKED_CAST")
    override fun onBindViewHolder(holder: ModelViewHolder<M>, position: Int) {
        with(holder) {
            bindData(modelList[position] as M)
            bindViews(modelList[position] as M, adapterListener)
        }
    }

    override fun submitList(list: List<Model>?) {
        list?.let { modelList = it }
        super.submitList(list)
    }
    
}

 

재활용하여 사용할 recyclerview adapter를 작성한다.

recyclerview adapter의 기본 사용방법에 대한 기록은 생략.

 

private val adapter by lazy {
    ModelRecyclerAdapter<BoardListModel, ArticleListViewModel> (
        listOf(),
        viewModel,
        resourcesProvider,
        adapterListener = object : BoardListListener {
            override fun onClickItem(model: BoardListModel) {
                //TODO
            }
        }
    )
}

 

위처럼 adpater를 정의하여 사용하면 된다.

 

 

코드 전문

https://github.com/YeseopLee/AllofMe/tree/feature/ArticleListFragment

 

 

Reference

https://github.com/Fastcampus-Android-Lecture-Project-2021/aop-part6-chapter01

'Android > Tips' 카테고리의 다른 글

툴바(ToolBar) 구현, Toolbar VS Layout  (0) 2021.12.13
RecyclerView에 animation 효과 주기  (0) 2021.12.04
TabLayout  (0) 2021.11.15
Retrofit2 Multiple BaseUrl (Java)  (0) 2021.03.25
ViewPager2 오버랩 화면전환 (pageTransformer)  (0) 2021.01.05
    'Android/Tips' 카테고리의 다른 글
    • 툴바(ToolBar) 구현, Toolbar VS Layout
    • RecyclerView에 animation 효과 주기
    • TabLayout
    • Retrofit2 Multiple BaseUrl (Java)
    Seoplee
    Seoplee
    개발공부를 하며 기록할만한 것들을 정리해놓은 블로그입니다.

    티스토리툴바