안드로이드 리스트뷰 아이템 정렬하기 1. (Android ListView Item Sorting 1) [Comparator, Collections]

2016. 9. 13. 15:55


1. ListView 아이템 다루기

앞선 몇 가지 ListView 예제들에서 ListView의 아이템을 다루는 다양한 방법에 대해 살펴보았습니다. ListView에 새로운 아이템을 추가하거나, 이미 추가된 아이템을 수정 또는 삭제하는 예제를 작성하고, 그 결과를 확인할 수 있었습니다.


또한 [안드로이드 리스트뷰 아이템 추가,수정,삭제]에서 Adapter의 역할에 대해 다시 한번 정리하면서, ListView의 아이템을 처리하는 주체가 Adapter이고, 그 Adapter를 통해 처리된 아이템 데이터가 화면에 표시(갱신)됨으로써 추가,수정,삭제 기능이 완성된다는 것을 설명하였습니다.


여기서 설명하고자 하는, ListView 아이템을 정렬하는 방법 또한, 앞선 예제들의 내용에서 크게 벗어나지 않습니다. Adapter를 통해 데이터에 접근한 다음 데이터 리스트를 정렬하고, 변경된 리스트를 화면에 다시 그리도록 만들기만 하면 됩니다.

안드로이드 리스트뷰 아이템 정렬


2. 안드로이드(Java)에서의 리스트 정렬

안드로이드(Java)에서 제공하는 리스트 자료구조를 위한 클래스는 여러 가지가 있지만, ArrayList 클래스(java.util.ArrayList)가 가장 많이 사용됩니다.

ArrayList 클래스


API Level 23까지의 ArrayList에는 add(), clear(), get(), size(), remove(), set() 등과 같이 java.util.List 인터페이스로부터 상속받은 기본 리스트 함수들이 구현되어 있지만, 리스트 정렬을 위한 함수가 자체적으로 제공되고 있지는 않습니다. (하지만 API Level 24부터 ArrayList클래스에 sort() 함수가 추가되었습니다.) 대신, ArrayList의 데이터를 정렬하기 위해 Collections 클래스(java.util.Collections)의 sort함수를 사용할 수 있습니다.

Collections 클래스


    void sort (List<T> list, Comparator<? super T> c)

보통 "리스트를 정렬한다"는 것은, 루프를 돌며 리스트를 "탐색"하여, 임의의(randomly) 순서로 저장된 리스트 데이터를 "정해진 규칙"에 따른 순서로 "재배치"하는 것을 의미합니다. 여기서 "정해진 규칙"이란 데이터의 순서를 결정할 조건을 말하는데, "정수형 데이터를 비교하여 작은 값부터 큰 값 순서로"(ASC, 오름차순) 이라던가, "문자열 데이터를 알파벳 순서에 따라 큰 값에서 작은 값 순서로"(DESC, 내림차순) 등의 규칙을 말합니다.

정수와 문자열의 오름차순, 내림차순 의미


그런데 정렬 과정에서 사용되는 규칙은 매우 주관적인 내용입니다. 즉, 어떤 값을 기준으로 어떤 조건을 사용할지는 절대적인 기준으로 정해진 것이 아니라, 개발자가 상황에 따라 정하는 것입니다. 그러므로 Collections.sort() 함수를 사용하여 리스트를 정렬할 때, 데이터의 순서를 결정할 규칙이 필요하다는 것을 눈치 채셨을 것입니다.


이 시점에, Collections.sort() 함수의 두 번째 파리미터인 Comparator를 주목해야 합니다. 위에서 언급한 주관적인 규칙을 sort() 함수에 전달하는 방법이 바로 Comparator이기 때문이죠.


정리하자면, 객관적으로 구현이 가능한 리스트 탐색(루프 실행) 및 리스트 데이터 재배치(메모리 참조 또는 인덱스 조절)는 Collections.sort() 함수 내부에 이미 구현되어 있으므로, 개발자가 할 일은 재배치가 필요한지를 결정하기 위한 조건(데이터 값 비교)을 Comparator를 통해 전달하는 것 입니다.

3. Comparator 인터페이스

Comparator 인터페이스는 이름 그대로 객체의 비교(참조 비교 또는 값 비교)가 필요한 곳에서 사용되는 인터페이스입니다. 주로 Comparator 인터페이스의 compare() 함수를 override하여 두 객체를 비교합니다.

    abstract int compare (T o1, T o2)

compare() 함수가 수행하는 역할은 전달된 객체 o1과 o2를 비교하여, 그 결과를 int 형으로 리턴하는 것입니다. 이 때, 리턴되는 결과 값은 음수(-), 0, 양수(+)로 구분되며, 각각 첫 번째 객체가 두 번째 객체에 비교하여 "보다 작음", "같음", "보다 큼"의 의미를 가집니다.


* 음수(-) 값이 리턴되는 경우. ( < 0) : o1 이 o2 보다 작음. (o1 < o2)
* 0 값이 리턴되는 경우 ( == 0) : o1 과 o2 가 같음. (o1 == o2)
* 양수(+) 값이 리턴되는 경우. ( > 0) : o1 이 o2 보다 큼. (o1 > o2)


그런데 위의 설명만으로는 Collections.sort() 함수에서 데이터 정렬 방향(오름차순 또는 내림차순)이 어떻게 결정되는지 쉽게 이해되지 않을 수 있습니다. 그래서 Collections.sort()의 정렬 과정에서 Comparator.compare() 함수의 리턴 값이 어떤 의미를 가지는지 쉽게 이해할 수 있도록 다음과 같이 의미를 수정하였습니다.


* 음수(-) 값이 리턴되는 경우. ( < 0) : o1 이 o2 의 앞에 와야 함.
* 0 값이 리턴되는 경우 ( == 0) : o1 과 o2 의 순서 변경 안함.
* 양수(+) 값이 리턴되는 경우. ( > 0) : o1 이 o2 의 뒤에 와야 함.


아래 그림은 리스트를 오름차순으로 정렬하고자 할때, compare() 함수가 어떻게 작성되어야 하는지를 나타내는 코드와 설명입니다. 만약 아래 코드를 내림차순으로 바꾸고자 한다면, 첫 번째 if문의 조건 비교를 반대로 하거나, 리턴 값 1과 -1의 위치를 서로 바꾸면 되겠죠.

compare() 함수의 해석


4. Comparator 인터페이스 사용하기.

Comparator 인터페이스를 만들고 Collections.sort() 함수를 호출하여, 문자열로 구성된 리스트를 정렬하는 코드를 작성하는 절차는 다음과 같습니다.


먼저, ArrayList로 선언된 데이터 리스트가 있다는 것을 가정합니다.

[STEP-1] ArrayList 데이터 준비
    ArrayList<String> strList = new ArrayList<String>() ;
    strList.add("B") ;
    strList.add("C") ;
    strList.add("A") ;

다음, Comparator 인터페이스를 상속받은 익명(Anonymous) 클래스의 인스턴스를 생성하여 compare() 함수를 override합니다. (예제에서는 편의상 익명 클래스를 사용하였으나, 상황에 따라 Comparator 인터페이스를 상속받는 클래스를 명시적으로 정의해야 하는 경우도 있음을 주의하세요.) 

참고로 아래 코드는 문자열을 오름차순으로 정렬하기 위한 코드입니다. 만약 내림차순으로 변경하고자 한다면 o1와 o2의 위치를 바꾸면 됩니다. 보다 명확한 이해를 위해 String.compareTo() 함수의 리턴 값의 의미를 찾아보시기 바랍니다. (https://developer.android.com/reference/java/lang/String.html)

[STEP-2] Comparator 인터페이스를 상속한 익명(Anonymous) 클래스 생성. 
    Comparator<String> cmpAsc = new Comparator<String>() {

        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2) ;
        }
    } ;

Comparator 인터페이스를 상속한 클래스의 인스턴스가 준비되었다면 Collections.sort() 함수를 호출하여 리스트를 정렬할 수 있습니다.

[STEP-3] Collections.sort() 함수 호출.
    Collections.sort(strList, cmpAsc) ;

정렬이 정상적으로 이루어졌는지 확인하기 위해, 루프를 돌며 strList 값을 확인해보겠습니다.

[STEP-4] 정렬된 데이터 확인.
    for (String str : strList) {
        System.out.println(str) ;
    }

다음과 같이 문자열 리스트가 정렬되어 출력되는 것을 확인할 수 있습니다.

A
B
C

5. 참고.


ANDROID 프로그래밍/LISTVIEW