일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- ar vr 차이
- 멤버변수
- 안드로이드 유닛 테스트 예시
- 안드로이드 라이선스 종류
- 스택 큐 차이
- 서비스 vs 쓰레드
- 클래스
- rxjava cold observable
- 안드로이드 레트로핏 사용법
- jvm 작동 원리
- 큐 자바 코드
- 안드로이드 유닛테스트란
- Rxjava Observable
- 서비스 쓰레드 차이
- 2022 플러터 설치
- 안드로이드 os 구조
- jvm이란
- android ar 개발
- 안드로이드 라이선스
- ANR이란
- rxjava disposable
- rxjava hot observable
- 안드로이드 레트로핏 crud
- 안드로이드 유닛 테스트
- 스택 자바 코드
- 2022 플러터 안드로이드 스튜디오
- android retrofit login
- 플러터 설치 2022
- 자바 다형성
- 객체
- Today
- Total
나만을 위한 블로그
[Android] 리사이클러뷰 페이징 처리 (페이징 라이브러리 X) 본문
페이징 라이브러리를 사용하지 않고 리사이클러뷰만으로도 충분히 페이징 처리가 가능하다.
대신 페이징 처리하려면 내가 꼭 알고 있어야 하는 값 2가지가 있다. 백엔드 개발자가 API 안에 넣어서 줄 것이다.
- 한 번에 몇 개의 데이터를 불러올 건지
- 몇 번째 페이지를 요청할 건지
편의상 한 번에 불러올 데이터의 양은 limit, 서버에 요청하는 페이지는 page로 쓴다.
형태는 조금씩 차이가 있겠지만 API 응답값을 확인하면 대충 아래와 비슷한 형태일 것이다.
{
"page": 1,
"limit": 20,
"totalCount": 1342,
"data": ...
}
클라이언트가 몇 번째 페이지를 요청했는데, 한 번에 가져갈 데이터는 몇 개고, 총 데이터는 몇 개인지, 요청한 페이지의 데이터는 어떤 것이 있는지 등을 보내줄 것이다.
리사이클러뷰를 사용한 페이징 처리는 addOnScrollListener()라는 함수를 통해 구현할 수 있다. 예를 들어 아래 코드처럼 작성할 수 있다.
myRecyclerView.apply {
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val lastVisibleItemPosition =
(recyclerView.layoutManager as LinearLayoutManager?)!!.findLastCompletelyVisibleItemPosition()
val itemTotalCount = recyclerView.adapter!!.itemCount
if (lastVisibleItemPosition >= itemTotalCount - 1) {
if (page * 10 < totalItemCount) {
page++
requestDTO.pages = page
myFunction(requestDTO)
}
}
}
})
.
.
.
}
하나씩 확인해 본다.
- lastVisibleItemPosition : 현재 리사이클러뷰에서 가장 마지막(맨 밑)에 표시되는 아이템의 position이다. 이 위치를 기준으로 page 변수값에 +1을 해서 새 데이터를 가져올 것이다
- itemTotalCount : 어댑터로 넘어간 리스트의 크기다. 만약 limit가 50개라면 여기서 50을 리턴할 것이고, 페이징 데이터를 한 번 추가로 받아왔다면 100이 표시될 것이다. 이 값에서 1을 빼서 마지막 아이템의 이전 아이템 position을 보게 한다
- 맨 밑에 위치한 아이템의 position이 itemTotalCount - 1보다 크거나 같을 경우, page 변수값에 10을 곱한 값이 총 아이템 개수보다 작은 경우 page 변수값을 +1해서 서버에 요청한다
이 중 findLastCompletelyVisibleItemPosition()의 역할은 아래와 같다.
마지막으로 완전히 보이는 뷰의 어댑터 위치를 반환한다. 이 위치에는 마지막 레이아웃 패스 이후에 전달된 어댑터 변경사항이 포함되지 않는다. 경계 검사는 현재 방향에서만 수행된다. 즉 레이아웃 매니저가 수평인 경우 뷰의 왼쪽 및 오른쪽 가장자리만 확인한다
그리고 어댑터에 데이터를 넘긴다. totalItemCount는 var 전역변수로 선언하고 0으로 초기화하고, 서버에서 데이터를 땡겨왔을 때 총 데이터 개수를 totalItemCount에 담아둔다.
아래는 예시 코드다.
viewModel.apply {
myFunction(requestDTO)
myState.collect {
when (it) {
is State.Success -> {
it.data?.let { data ->
val result = data.result
totalItemCount = data.totalCount
if (result.isNotEmpty()) {
list.addAll(result)
initAdapter(list)
}
}
binding.isLoading = false
}
is State.Error -> {
it.message?.let { message ->
showMessage(message)
}
binding.isLoading = false
}
is State.Loading -> { binding.isLoading = true }
}
}
}
private fun initAdapter(list: ArrayList<RequestDTO>) {
recyclerViewState = binding.myRecyclerView.layoutManager?.onSaveInstanceState()!!
myAdapter = MyAdapter(requireActivity(), list)
binding.myRecyclerView.apply {
setHasFixedSize(true)
adapter = myAdapter
layoutManager?.onRestoreInstanceState(recyclerViewState)
}
}
initAdapter() 안의 recyclerViewState는 전역변수로 선언한 lateinit var Parcelable 프로퍼티인데, 페이징으로 새 데이터를 가져오면 리사이클러뷰 마지막에 있던 스크롤이 갑자기 맨 위로 이동해버린다. 이것을 막고 마지막 스크롤했던 위치를 기억해뒀다가, 새 데이터들을 가져오면 첫번째 새 데이터부터 스크롤할 수 있게 해주는 장치다.
자세한 내용은 아래 포스팅을 참고하면 된다.
https://onlyfor-me-blog.tistory.com/361
이렇게 하면 페이징 처리가 되서 바닥까지 스크롤하면 새 데이터를 가져와서 화면에 보여줄 것이다.
'Android' 카테고리의 다른 글
[Android] Coroutine의 Job과 Dispatchers란? (0) | 2023.01.31 |
---|---|
[Android] LiveData observe()가 여러 번 호출되는 에러 해결 (0) | 2023.01.31 |
[Android] 지연 초기화, lateinit vs Lazy (0) | 2023.01.28 |
[Android] 리사이클러뷰가 있는 레이아웃의 성능 향상 - 1 - (0) | 2023.01.26 |
[Android] hilt 사용 시 Cannot create an instance of class ViewModel 에러 해결 (0) | 2023.01.25 |