본문 바로가기

안드로이드 Android

안드로이드 개발 (25) - Coroutine Job 사용과 AutoCompleteTextView를 사용한 검색 기록 보기

https://gift123.tistory.com/52?category=967702 

 

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

안녕하세요 Loner입니다. 오랜만에 글을 작성하게 됩니다. 최근에 많은 사건이 있었고, 수습하느라 정신이 없었네요 이포스팅은 최근에 겪은 문제를 참고해서 정리하는 글입니다. 페이징 처리를

gift123.tistory.com

 

https://gift123.tistory.com/53?category=967702 

 

안드로이드 개발 (24) - 페이징 처리 실제 구현

https://gift123.tistory.com/52 안드로이드 개발 (23) - 페이징 처리 1편 안녕하세요 Loner입니다. 오랜만에 글을 작성하게 됩니다. 최근에 많은 사건이 있었고, 수습하느라 정신이 없었네요 이포스팅은 최

gift123.tistory.com

안녕하세요 Loner입니다.

저번 편에서 페이징 처리가 들어간 검색 목록을 만들었습니다. 이어서 추가적인 기능을 설명하는 내용입니다.

 

저번 편까지 뼈대가 되는 페이징 처리의 로직과 실제 프레임워크에서 어떻게 구현을 할지 만들어봤습니다. 

그야말로 뼈대를 설명했기 때문에 그 이후에 어떻게 만들어갈지는 사람마다 다를겁니다. 이번엔 제가 추가로 설정한 기능들에 대해 설명을 해보겠습니다. 

 

1. Coroutine의 Job를 사용한 addTextChangedListener 내부 로직 컨트롤 

이 프로젝트는 아래 처럼 텍스트를 적으면 알아서 검색이 되는 구조입니다. 

저번 편에서 addTextChangedListener안에 api 호출하는 함수를 넣어서 EditText의 text가 하나라도 바뀔때마다 실행이 되게끔 했습니다. 

하지만 이와 같이 구현을 해놓으면 문제점이 너무 많은 api호출이 일어난다는 점입니다. 

 

예를들어서 사용자가 한글로 안녕하세요를 검색한다고 했을 때 

ㅇ ..아 .. 안.. 안ㄴ.. 안녀 .. 안녕....안녕ㅎ.. 한글자라도 추가되면 계속 api 호출이 일어납니다.

 - ㅇ 검색 -> 아 검색 -> 안 검색 -> .....

 

페이지네이션의 가장 근본은 많은 데이터를 한꺼번에 불러오지 않게해서 db과부하를 줄이기 위함입니다.

근데 위처럼 아무런 조치를 취하지 않는다면 클라이언트의 db를 여러번 호출하기 때문에 db 과부하가 똑같이 일어나는 현상이 됩니다.

(서버 개발자님이 페이지 네이션하려고 백단에서 다 열심히 구조를 만들어놧을탠데... 의미가 사라진다.)

 

 

그렇다면 어떻게 해야하는가? 

일단 목표는 사용자가 원하는 단어를 적었을 때만 그때 Api함수를 호출하게끔 해야합니다.

즉, 글을 적고 있을땐 Api호출을 막아야하고 글을 다 적고난 뒤,

잠시 글쓰기가 멈췃다면 마지막에서야 Api가 호출이 되야합니다. 

 

addTextChangedListener는 text가 바뀔때마다 호출이되는 함수인데 내부적으로 어떻게 건드려야할까요? 

제 경우 코루틴을 사용했습니다. 

 

코루틴의 장점은 작업 취소가 된다는 점입니다. 

제어에 사용되는 Job 클래스 안에 코투틴 블록을 취소하기 위한 cancel() 함수가 존재합니다. 

이를 응용 했습니다.

null을 허용하는 job 객체를 만들어서 addTextChangedListener 실행시 job?.cancel()를 무조건 한번 실행했습니다. 

그다음 job = lanch{ delay(1000) ... 로직}  job 객체에 작업할 내용을 초기화 시켜줍니다.

실행지연을 1초정도 걸어서 만약 1초내에 다시 addTextChagnedListener가 호출되지 않는다면 이전에 예약된 작업을 실행하도록 했습니다. 

 

그래서 위 같은 로직으로 만든다면 "ㅇ" , "아" "안"...으로 모두 api 호출이 되지않고 "안녕" 을 적고 1초뒤에 반복 호출 없이 한번의 호출로 "안녕"에 대한 결과물들을 받아올 수 있습니다. 

 

코드로는 아래와 같이 작성이 됩니다.

예제

    private fun EditText.afterTextChangedCustom(delay: Long, search: (String) -> Unit) {
        var job: Job? = null
        this.addTextChangedListener {
            it ?: return@addTextChangedListener
            job?.cancel()
            job = lifecycleScope.launch {
                delay(delay)
                search(it.toString())
            }
        }
    }

 

    etSearch.apply {
            afterTextChangedCustom(1000) { itemFetch(ItemFetchMode.SEARCH, it) }
            ...
            }

 

이로써 효율적인 검색이 가능해집니다. 

 

변경 후 

 


2. AutoCompleteTextView를 활용한 검색 기록 보기 

이전까지 기본적으로 EditText를 사용했지만 AutoCompleteTextView를 대신 사용해봅시다. 

AutoCompleteTextView는 EditText를 상속받아 만들어진 자식클래스 입니다. 그래서 Solid의 원칙 리스코프의 치환 법칙을 떠올리며.. 위대한 갓 구글 안드로이드팀은 분명 부모클래스를 하위클래스가 대체할 수 있게끔 잘 만들었을겁니다. 그래서EditText를 지우고 AutoComplteTextView를 대신 사용해도 문제없이 텍스트 입력이 가능합니다. 

 

그렇다면 다른점은? 바로 텍스트를 세로형식으로 스피너처럼 나열하는 표시를 만들 수 있습니다. 

AutoComplteTextView는 어댑터 패턴을 사용해서

이 스피너처럼 나열되는 UI 리스트의 아이템을 설정할 수 있도록

언제든지 어댑터를 이용해서 만드거나 변경할 수 있습니다.

 

아래는 안드로이드 공식 샘플(JAVA)입니다. 

         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                 android.R.layout.simple_dropdown_item_1line, COUNTRIES);
         AutoCompleteTextView textView = (AutoCompleteTextView)
                 findViewById(R.id.countries_list);
         textView.setAdapter(adapter);
     }

     private static final String[] COUNTRIES = new String[] {
         "Belgium", "France", "Italy", "Germany", "Spain"
     };

이 포스팅의 경우 addTextChangedListener에서 검색에 성공했을때 어댑터에 검색어를 추가를 해서 

autoComplteTextView.setAdatper(adapter) 를  해주면 됩니다.

 

예제

textList.add(검색한단어)
autoTextView.
setAdapter(ArrayAdapter(this.context,android.R.layout.simple_dropdown_item_1line,textList!!))

결과

 

 

3. 마무리

이제 기존 페이징 처리에서 텍스트 자동완성 기능과

불필요한 검색어 호출을 줄일 수 있음으로 사용자를 위한 서비스로 한발자국 가까워 졌습니다.

 

다음은 페이징처리를 안드로이드 권장 아키텍쳐를 응용해서 어떻게 코드를 작성하는것이 좋은 방법인가에 대해 고찰을 해보도록 하겠습니다. 이상입니다.