마커 클러스터링

https://navermaps.github.io/android-map-sdk/guide-ko/5-8.html

화면에 대량의 마커가 노출되면 성능이 저하될 뿐만 아니라 여러 마커가 겹쳐서 눈에 쉽게 보이지 않을 것이다. 이때 사용할 수 있는 것이 마커 클러스터링이다.

키 정의

마커 클러스터링 기능을 이용하려면 데이터의 키를 의미하는 ClusteringKey 인터페이스를 구현한 클래스를 정의해야 한다. ClusteringKey 인터페이스는 데이터의 좌표뿐만 아니라 두 데이터가 동일한지를 정의한다. 따라서 이 인터페이스를 구현하는 클래스는 equals() 및 hashCode()도 구현하는 것이 권장된다.

image.png

아래가 문서에 나와있는 ClusteringKey를 구현하는 클래스를 정의하는 예제인데 코틀린의 data class를 이용하면 equals()hashCode()를 굳이 구현하지 않아도 될 것 같다.

class ItemKey(val id: Int, private val position: LatLng) : ClusteringKey {
    override fun getPosition() = position

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || javaClass != other.javaClass) return false
        val itemKey = other as ItemKey
        return id == itemKey.id
    }

    override fun hashCode() = id
}

data class는 equals(), hashCode(), toString(), componentN(), copy()를 기본적으로 구현해주기 때문이다.

data class ItemKey(val id: Int, private val position: LatLng) : ClusteringKey {
    override fun getPosition() = position
}

나는 ClusteringKey가 해당 마커가 어떤 정보를 가지고 있는지를 정의하는 것이라고 이해했다. 프로젝트에서 마커는 픽의 정보를 가지고 있어야 하므로 아래처럼 키를 정의했다.

data class MarkerKey(val pick: Pick) : ClusteringKey {
    override fun getPosition() = LatLng(pick.location.latitude, pick.location.longitude)
}

Clusterer 객체

실제 클러스터링 동작은 Clusterer 객체가 수행한다. 이 클래스의 인스턴스는 직접 생성할 수 없고 Clusterer.BuilderClusterer.ComplexBuilder 빌더 클래스를 사용하여 생성할 수 있다. Clusterer.Builder는 데이터의 키를 의미하는 타입 파라미터가 필요하므로 앞서 정의한 클래스(ItemKey)를 지정하고, build()를 호출하면 Clusterer 객체가 생성된다.

image.png

val clusterer: Clusterer<ItemKey> = Clusterer.Builder<ItemKey>().build()

Clusterer.Builder로 생성한 Clusterer 객체는 기본적인 기능을 제공하고, Clusterer.ComplexBuilder로 생성한 Clusterer 객체는 복잡한 전략과 기능을 제공한다. 말만 들어서는 잘 모르겠지만 각각의 공식문서에서 제공하는 메서드를 보면 확실히 차이가 있음을 알 수 있다.