Recycler View에 초간단 Paging 라이브러리 적용하기

2021. 6. 9. 15:48개발을 파헤치다/Android

반응형

Recycler View는 어떤 서비스에서든지 한번 정도는 쓰이는 녀석인데요.

그도 그럴 것이 데이터 목록을 보여주는 건 대다수의 서비스에 존재합니다.

적게는 수 백, 많게는 수 만 건이나 되는 데이터를 한 번에 불러올 수 없기에 (물론 그럴 필요도 없죠)

잘게 쪼개어 나누어주는 Paging 작업을 하는데요. 

이번에는 굉장히 편하게 Recycler View에 Paging을 적용할 수 있는 라이브러리를 소개해드리고자 합니다.

 

시작하기 전에, Recycler View는 구현하셨나요?

Recycler View를 잘 모르겠다 싶으신 분들은 여기를 눌러서 기본 사용법부터 보고 오시는걸 추천드립니다.

그래야 이해할 수 있거든요.

그리고 혹시 Google에서 공식적으로 제공하는 Paging 라이브러리가 궁금하신 분들은 여기를 눌러주세요.

 

설치하기

// App Level build.gradle
dependencies{
   ...
   implementation "com.github.markomilos:paginate:1.0.0"
   ...
}

 

설치는 매우 쉽습니다.

App 디렉토리 밑에 있는 build.gradle 파일에 위와 같이 딱 한 줄 추가해주고 Sync Now 누르시면 됩니다.

 

 

적용하기

이제 Activity에서 어떻게 적용할지 한번 살펴보도록 하죠.

시작하기 전에 제가 개발 중인 앱에서는 MVP 아키텍처를 사용하고 있습니다.

또한, Recycler View를 그룹화시켜서 보여주기 위해 Groupie라는 라이브러리를 사용하고 있는데요.

기존 Recycer View에 적용하는 것과 크게 다른 부분이 없으니 코드와 주석을 잘 읽어보시면

무리 없이 적용할 수 있습니다.

// Activity에 Paginate.Callbacks를 상속하여 구현해야 합니다

class CommentActivity : BaseActivity(), CommentContract.View, Paginate.Callbacks {
    val TAG = CommentActivity::class.java.simpleName
    
    // Groupie Adapter로 기존 Recycler View Adapter와는 다릅니다
    val groupAdapter = GroupAdapter<GroupieViewHolder>()
    
    var mPresenter : CommentPresenter? = null
    var mBinding: ActivityCommentBinding? = null
    
    // Paging 숫자 변수
    var parentCommentPageNum: Int? = 1
    // 현재 데이터를 로딩중인지 상태체크하는 변수
    var loading: Boolean = false


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityCommentBinding.inflate(layoutInflater)
        mBinding = binding
        setContentView(binding.root)
         // Presenter 초기화
        mPresenter = CommentPresenter(contentRepository = ServiceLocator.provideContentRepository(),
            commentView = this)
       
        mPresenter!!.onCreate(intent)
        // 댓글 리스트 초기화
        initCommentList()

    }

    // Recycler View 초기화
    fun initCommentList(){
        // View Binding 적용
        val commentRecyclerView = mBinding!!.commentRecyclerView
        commentRecyclerView.layoutManager = LinearLayoutManager(this)
        commentRecyclerView.adapter = groupAdapter

       // Paging 설정
        Paginate.with(commentRecyclerView, this)
                // 몇개의 아이템을 보여주고 다음 아이템을 불러올지 설정하는 값
                .setLoadingTriggerThreshold(10)
                // true로 설정하면 기존 설정한 Adapter에 기능이 추가됩니다
                // 로딩아이콘 표시 및 아이템 변경시 알아서 처리해줍니다
                // 하지만 Groupie Adapter는 호환되지 않아
                // 로딩아이콘이 사라지지 않는 현상이 발생하기때문에 false로 설정했습니다
                // 기본 Adpater를 사용하시면 true로 설정하시면 됩니다
                .addLoadingListItem(false)
                .build()*
    }

    // 댓글을 Adapter에 추가하는 콜백 메서드
    // API 호출을 통해 데이터를 가져옵니다. 
    // 댓글 리스트와 다음에 불러올 Page 번호값을 받아 처리합니다.
    override fun addParentCommentList(data: List<Comment>, nextPage: Int?) {
        for(i in data){
            val parentCommentItem = ParentCommentItem(i)
            groupAdapter.add(ExpandableGroup(parentCommentItem))
        }

        // 다음에 불러올 데이터 페이지 번호를 설정합니다. 없는 경우 null이 들어갑니다
        parentCommentPageNum = nextPage
        // 페이징 라이브러리 로딩중 상태를 변경해줍니다.
        //  그래야 로딩중에 또 onLoadMore가 호출되는 것을 방지할 수 있습니다.
        loading = false
    }

    /*
    *  Paging Library Callback 구현
    * */

    // 다음 댓글을 불러온다
    override fun onLoadMore() {
        loading = true
        val content = intent.getSerializableExtra("content") as Content
        // Presenter에 댓글을 요청합니다. 
        // API 호출을 통해 가져오면 Presenter에서는 addParentCommentList를 호출해줍니다
        mPresenter?.getParentCommentList(contentId = content.id!!, page = parentCommentPageNum!!)
    }

    // 현재 댓글 데이터를 불러오고있는지 확인합니다
    // 지속적으로 콜백함수가 호출되기 때문에 여기에서 로딩중 처리를 해놓지 않으면 onLoadMore()가
    // 여러번 호출이 됩니다
    override fun isLoading(): Boolean {
        return loading
    }

    // 더 이상 가져올 댓글이 없는지 확인한다
    override fun hasLoadedAllItems(): Boolean {
        return  parentCommentPageNum == null  // 더 이상 가져올 댓글이 없으면 true를 리턴합니다

    }
}

생각보다 간단히 적용이 되었죠?

구현할 것도 그렇게 많지 않고 쉽고 직관적으로 적용이 되어

빠르게 Paging을 구현해야 할 때 사용하면 편리할 것 같습니다.

 

이렇게 다양한 Layout과 Orientation에도 적용 가능하니 활용도가 꽤 있다고 볼 수 있습니다.

해당 라이브러리가 어떻게 동작하는지 동작원리에 대해 궁금하시다면 여기를 눌러 확인해보세요.

또 궁금하신 점이 있다면 언제든 여기로 편하게 물어봐주세요. 기쁜 마음으로 답변드리겠습니다 :)

 

반응형