본문 바로가기

안드로이드 Android

안드로이드 개발 (23) - 페이징 처리 로직

안녕하세요 Loner입니다. 오랜만에 글을 작성하게 됩니다.

최근에 많은 사건이 있었고, 수습하느라 정신이 없었네요 이포스팅은 최근에 겪은 문제를 참고해서 정리하는 글입니다.

페이징 처리를 해야되는 상황이 있었는데 페이징 처리를 어떻게 해야할지 살펴보도록 하겠습니다.

 

0. 페이징 처리를 왜 하는가?

 

페이징 처리의 경우 기본적으로 한꺼번에 많은 네트워크 호출을 피하기 위해서 사용합니다.

예를들어 리스트를 보여준다고 할때 사용자가 스크롤 하기전 최대로 볼 수 있는 아이템 갯수가 15개이지만 서버에 있는 전체 데이터량이 1만개라 했을때 이를 한꺼번에 다 클라이언트로 가져와서 데이터를 사용한다해도 사용자가 다 볼일이 없을수도 있고, 기본적으로 많은양을 가져오는것에 있어서 서버에 많은 과부하가 생깁니다.

 

그래서 사용자가 원하는 만큼만 상황에 맞게 보여준다면 DB의 불필요한

과부하를 줄일 수 있고 사용자가 보지 않았는데 미리 데이터를 가져올 필요도 없습니다.

 

1. Android에서 페이징처리를 하려면?

크게 두가지 방법이 있습니다.

(1) 기본적으로 jetPack에서 지원해주는 Paging 라이브러리를 사용한다.

(2) 필요한 갯수만큼 불러오는 로직을 스스로 만든다. 

 

이번에 구현하려했던 페이징 처리는

굳이 무거운 라이브러리를 가져오기 싫어서 

로직을 만드는 2번을 선택했습니다.

 

 

2. 페이징 처리를 이용한 구현 조건 

1) 검색창으로 단어를 검색하면 네트워크 db로부터 데이터를 가져와서 ui로 보여줄 것

 

2) 데이터를 가져올때 20 개씩 추가로 가져올 것 

 

3) 네트워크 서버로부터 DB를 가져올때 page , count 매개변수를 통해서 필요한 데이터와 갯수를 가져옵니다.

EX:  getData(page=1 , count= 20 ) ,getData( page = 2 , count =20 ) .... 페이지 수를 늘려가며 더 가져와야합니다.

 

4) 검색어가 바뀌면 기존 db는 삭제가 되고 다시 page = 1 , count = 20 부터 가져와야합니다. 

 

5) 검색 결과 데이터들을 보여주는 리스트가 맨 하단 아래 스크롤에 도착하면 다음 페이지의 데이터 20개를 가져와서

기존 데이터에서 추가가 됨 

 

결과물

결과물로 위와같이 나옵니다.

스크롤이 맨 아래에 내려오면 다음페이지의 데이터 20개를 추가로 불러옵니다.

 

위 같은 결과물을 만들기 전에

5가지 조건에 맞는 로직을 만들어야했습니다.

 

3. 페이징 처리 로직 

- 첫번째로 생각난 것은 page 객체를 만들어서 상황에 맞게 1씩 추가하거나 다시 1로 할당하거나를 생각했지만

  나중에 유지보수 할때 실수로 page 객체를 건드려서 부수적인 문제들이 계속나타날까봐 생각을 바꿧습니다.

 

- 두번째로 생각난 것은 빈틈없는 점화식으로 page객체를 사용하지 않고 페이징 처리를 하는것이었습니다.

  전역 객체를 하나라도 없애고 싶은 마음에 두번째 방식을 선택했습니다.

 

만든 로직은 다음과 같습니다.

 

현재 ui로 렌더링해서 사용되고 있는

데이타 총 갯수를 나누기 20를 해줍니다.

(데이타 갯수 / 20)

그러면 20개면 1, 40개면 2, 60개면 3 .... 

 

즉 현재 데이터갯수만으로 현재 페이지를 알 수가 있습니다.

 

그렇다면 api의 매개변수로  page , count를 설정해서 데이터 리스트를 가져온다 했을 때

 

Api (page = (currentSize/20) + 1 , count = 20) 로 

page객체를 따로 써서 컨트롤하지 않아도

이미 불러온 데이터 갯수에 따라 다음페이지를 꾸준히 가져올 수 있습니다.

 

 

페이징 처리 테스트 코드

    @Test
    fun `API검색시_페이지_변경_로직_체크`(){

        val list = mutableListOf<Int>()
        assertEquals((list.size/20),0)
        repeat(20){
            list.add(it)
        }
        assertEquals((list.size/20),1)
        repeat(20){
            list.add(it)
        }
        assertEquals((list.size/20),2)
    }

혹시나 UnitTest에 대해 모르시는 분들을 위해 말씀드리자면

assertEquals()의 첫번째 인자는 결과값, 두번째 인자는 예상값 입니다. 

두 값이 다르면 false 고 같다면 true로 확인됩니다.

위 테스트 코드는 실패 없이 모두 true입니다. 

 

  val list = mutableListOf<Int>()
        assertEquals((list.size/20),0)
          repeat(20){
            list.add(it)
        }

맨처음 검색하기전 데이터 갯수가 0일 때 20을 나누면 당연히 0으로 떨어집니다.

assertEquels는 true 였습니다.

 

여기서 page = (list.size/20)+1 , count =20 를 한다면 결국,

page= 1 , count =20 이기 때문에 

첫 검색시 기본적으로 1번 페이지의 데이터를 가져올 수 있습니다. 

(위 코드는 로컬 테스트 코드 이기 때문에 실제 api page = 1 , count = 20 를 넣지 않고 반복문으로 데이터를 추가했습니다.) 

 

     assertEquals((list.size/20),1)
        repeat(20){
            list.add(it)
        }

그렇다면 이미 한번 데이터를 가져왔다면 현재 데이터 갯수는 총 20일 겁니다. 

이 상태에서 20 나누기 20 을 하면 1이 나옵니다. assertEquls는 true가 됩니다.

 

마찬가지로 page= (list.size/20) +2 를 한다면 사실상

getData(page = 2 ,count = 20)로 검색하게 됩니다. 

 

이런식으로 꾸준하게 현재 데이터 갯수를 기준으로

다음 페이지 번호를 계산이 된다는것을 테스트 코드를 통해 확인했습니다.

 

4. 페이징 처리 조건 충족 

이제 터치로 스크롤해서 데이터 끝에 도달하는 순간 현재 size를 이용해서

(현재사이즈/20)+1를 Api의 page 매개변수에 넣어서 다음 데이터를 가져오면 됩니다. 

 

4번째 조건 이었던 검색어 변경시 데이터를 모두지우고 Api (page= 1 , count =20)로 불러와야 하는 경우는 
검색 기능을 통해서 데이터를 가져올때 기존 데이터를 삭제해주고 Api(page =1 , count = 20)을 적용하면 됩니다.

 

이제 (현재데이터 사이즈/20)+1 를 Api 매개변수 page에 넣어주고 나머지는 프레임 워크 특성을 이용해서

콜백 리스너만 잘 설정해주면 1~5번의 문제는 모두 충족하며 구현 할 수 있습니다.

 

다음편에서 프레임워크 상황에서 어떤식으로 구현을 해가는지 살펴보도록 하겠습니다.

(EditText, AutoCompleteTextView, RecyclerView,외 라이브러리 하나 사용예정 )