[Google Map] addMarker 성능(속도) 개선이 가능한가?
addMarker 성능 속도 개선에 대한 이슈
addMarker를 사용하여 구글맵에 마커를 표기하는 과정에 문제가 발생하였다. 바로 성능 문제이다. 몇개 안되는 경우에 바로 바로 맵에 그렸다. 하지만 지도에 표기해야할 마커 개수가 늘어날 수록 속도는 느려지기 시작하였다.
반경 5km 이내로 잡아서 표기하면 그래도 봐줄만한 속도가 나온다. 하지만 전체를 기준으로 혹은 반경 30km 이내로 선택하게되면 스피너도 멈춤현상이 발생하고, 몇 분 걸린다. 구글맵에 표기해야할 마커 개수는 현재까지 약 3,000개 정도 된다. 그 중에 현재 작업이 완료된 데이터 개수는 900개 정도인데… 속도가 너무 느리다. 해결책이 필요했다.
스레드를 사용하지 않았더니, 콤보박스(스피너)에서 “-전체-“를 선택한 경우 멈춤현상이 발생했고, 마커를 다 추가한 후에 멈춤 현상이 풀리고, 지도에 표기되었다. 사용자에게 UI멈춤 현상은 부정적으로 다가오기때문에 처리가 필요하여스레드를 사용하여 멈춤 현상을 해결하였다. 사용자에게 작업중임을 알리기 위해 프로그래스 다이얼로그 노출을 추가하였다.
//DB에서 가져온 데이터 : tradeArr
if(tradeArr!=null&& tradeArr.length > 0) {
mMap.clear();//마커 추가전에 기존 마커들 제거을 위해 지도 클리어
mMap.getUiSettings().setMyLocationButtonEnabled(true);
if(mCurrentLocatiion == null) {
// 처음 시작위치 : 서울 시청 광장
Location location = new Location("");
location.setLatitude(37.56553);
location.setLongitude(126.97801);
mCurrentLocatiion = location;
}else{
//test code
// 처음 시작위치 : 서울 시청 광장
Location location = new Location("");
location.setLatitude(37.56553);
location.setLongitude(126.97801);
mCurrentLocatiion = location;
}
showProgressDialog(); //스레드 시작 전 다이얼로그 호출
//스레드 추가
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0; i<tradeArr.length;i++){
MarkerOptions marker = new MarkerOptions();
//현재 나의 위치 기준에서 50킬로 이내의 판매점만 가져온다.
Location targetLocation = new Location("");
targetLocation.setLatitude(tradeArr[i].getLatitude());
targetLocation.setLongitude(tradeArr[i].getLongitude());
//float distance = mCurrentLocatiion.distanceTo(targetLocation); //in meters
float distance = mCurrentLocatiion.distanceTo(targetLocation) / 1000; // in km
Log.d(DefaultSettings.TAG, "#### : 판매점과의 거리 : " + distance + "km");
if(_kilometer >= 1100){
if (Integer.parseInt(tradeArr[i].getWinCount()) >= 10) {
addMarkerFromDocument(tradeArr[i], marker);
}
}else if(_kilometer >= 1000){
if (Integer.parseInt(tradeArr[i].getWinCount()) >= 7) {
addMarkerFromDocument(tradeArr[i], marker);
}
}else {
if (_kilometer > 0 && _count > 0) { //전체 기준이 아닌경우
if ( distance <= _kilometer && Integer.parseInt(tradeArr[i].getWinCount()) >= _count) {
addMarkerFromDocument(tradeArr[i], marker);
}
} else if (_kilometer > 0 && _count < 1) {
if (distance <= _kilometer) {
addMarkerFromDocument(tradeArr[i], marker);
}
} else if (_kilometer < 1 && _count > 0) {
if (Integer.parseInt(tradeArr[i].getWinCount()) >= _count) {
addMarkerFromDocument(tradeArr[i], marker);
}
} else {
addMarkerFromDocument(tradeArr[i], marker); //전체 데이터
}
}
//showTotCorsePlacemark();
}
// 마커 지도에 추가 작업
runOnUiThread(new Runnable() {
@Override
public void run() {
for(int i =0; i<currentMarkerList.size(); i++){
mMap.addMarker(currentMarkerList.get(i)); //맵에 표시
}
hideProgressDialog(); // 다이얼로그 hide처리
}
});
}
}).start();
...생략
List<MarkerOptions> currentMarkerList;
............생략
private void addMarkerFromDocument(TradeInfoVo vo, MarkerOptions marker){
//Log.d(DefaultSettings.TAG, "#### : 마커추가 ");
//map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
marker.position(new LatLng(vo.getLatitude(), vo.getLongitude()));
marker.visible(true);
marker.title(vo.getTradeName());
marker.snippet(getAddress(new LatLng(vo.getLatitude(), vo.getLongitude())));
marker.icon(this.getMarkerIcon(vo.getWinCount())); //마커 이미지
currentMarkerList.add(marker);
}
현재 나의 위치와 거리의 계산식의 속도는 문제가 없다.
for 반복문 안에서 맵에 추가하는 mMap.addMarker(currentMarkerList.get(i)) 역시 속도 문제는 없다.
가장 시간을 많이 잡아먹는 로직은 for문안에서 MarkerOptions 데이터를 생성하는 addMarkerFromDocument() 메소드이다. 경도와 위도값을 가지고 주소 정보를 가져오는 로직과 마커아이콘을 가져오는 로직의 속도를 체크해보면 어느 부분이 느린지 나올 것 같다. 예상하건데 icon가져오는 쪽 문제일 확률이 높다. 예상은 빗나갔다. 아이콘 가져오는 부분에서는 속도 저하 문제가 없었다. 속도 저하문제는 경도와 위도값을 가지고 주소 정보를 조회해서 가져와 snippet에 적용하는 코드가 문제였다. 테스트 차원에서 snippet 정보를 “test”로 설정 후 확인한 결과 3초도 걸리지 않았다.
그렇다면, 경도와 위도값을 가지고 주소를 조회하는 로직의 속도를 빠르게 하는 방법을 찾아야했다. 제일 빠른 방법은 이 주소 정보 마져 데이터베이스에 등록하는 방법이다. 로직 상에서 해결할 수 있는 방법은 없을까??
■속도 이슈가 발생한 메소드
public String getAddress(LatLng latlng) {
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List<Address> addresses;
try {
addresses = geocoder.getFromLocation( latlng.latitude, latlng.longitude, 1);
} catch (IOException ioException) {
return "Geocoder 서비스 장애";
} catch (IllegalArgumentException illegalArgumentException) {
return "GPS 좌표 오류";
}
if (addresses == null || addresses.size() == 0) {
return "주소 없음";
} else {
return addresses.get(0).getAddressLine(0);
}
}
[관련자료]
https://github.com/mapbox/mapbox-gl-native/issues/5390
https://stackoverflow.com/questions/19346206/how-to-move-a-map-under-a-marker
https://stackoverflow.com/questions/30682723/how-stop-markers-from-blinking-android
https://developer.android.com/reference/android/location/Geocoder
https://developer.android.com/reference/android/location/Address.html
https://stackoverflow.com/questions/9409195/how-to-get-complete-address-from-latitude-and-longitude