배터리를 위한 위치 최적화

Android 8.0(API 수준 26)에 백그라운드 위치 액세스 제한이 도입되면서 위치 서비스 사용이 배터리 소모에 미치는 영향이 다시 주목을 받게 되었습니다. 이 페이지에서는 일부 위치 서비스 권장사항을 소개하고 앱의 배터리 효율성을 높이기 위해 현재 취할 수 있는 조치에 관해 설명합니다. 이런 권장사항을 적용하면 실행되는 플랫폼 버전과 관계없이 앱에 도움이 됩니다.

Android 8.0의 백그라운드 위치 제한은 다음과 같은 변경사항을 도입했습니다.

  • 백그라운드 위치 수집이 제한되고 위치가 연산되어 1시간에 몇 번만 전달됩니다.
  • Wi-Fi 검색은 그 빈도가 더욱 적고, 기기가 동일한 고정 액세스 포인트에 연결되어 있을 때는 위치 업데이트가 연산되지 않습니다.
  • 지오펜싱 응답은 몇십 초에서 약 2분 간격으로 변경됩니다. 이번 변경으로 배터리 성능이 눈에 띄게 개선되었습니다. 일부 기기의 경우, 배터리 성능이 10배까지 향상되기도 합니다.

이 페이지에서는 더욱 정확성이 높고 Framework Location API보다 배터리 부담이 적은 Google Location Service API를 사용하는 것으로 가정합니다. 특히, 이 페이지에서는 가속도계, 자이로스코프, 자기계 및 기타 센서는 물론이고 GPS, Wi-Fi, 모바일 네트워크의 신호를 결합하는 Fused Location Provider API를 잘 알고 있는 것으로 가정합니다. 또한 Fused Location Provider API 위에 빌드되고 배터리 성능에 최적화된 Geofencing API도 숙지하고 있어야 합니다.

배터리 소모에 관한 이해

위치 정보 수집과 배터리 소모는 다음과 같은 측면에서 직접적인 관련이 있습니다.

  • 정확성: 위치 데이터의 정밀도입니다. 일반적으로 정확성이 높을수록 배터리 소모가 큽니다.
  • 빈도: 위치가 연산되는 빈도입니다. 위치 연산 빈도가 높을수록 배터리를 더 많이 사용합니다.
  • 지연 시간: 위치 데이터가 전달되는 속도입니다. 일반적으로 지연 시간이 적을수록 더 많은 배터리가 필요합니다.

정확성

setPriority() 메서드를 사용하여 다음 값 중 하나를 인수로 전달하면 위치 정확성을 지정할 수 있습니다.

  • PRIORITY_HIGH_ACCURACY는 가장 정확한 위치를 제공합니다. 위치 정보는 필요에 따라 여러 가지 입력값을 사용하여 연산되는데(GPS, Wi-Fi, 셀을 사용 설정하고 여러 종류의 센서 사용), 배터리를 상당히 소모할 수 있습니다.
  • PRIORITY_BALANCED_POWER_ACCURACY는 전력 사용을 최적화하면서도 정확한 위치를 제공합니다. GPS는 거의 사용하지 않습니다. 일반적으로 Wi-Fi와 셀 정보를 결합하여 기기 위치를 연산합니다.
  • PRIORITY_LOW_POWER는 대체로 휴대폰 기지국을 사용하고 GPS와 Wi-Fi 입력값은 사용하지 않기 때문에 배터리를 최소한으로 사용하는 대략적인(도시 수준) 정확성을 제공합니다.
  • PRIORITY_NO_POWER는 다른 앱에서 이미 연산되어 있는 위치 정보를 수동적으로 수신합니다.

대부분 앱에서 필요한 위치 정보는 균형 잡힌 전력 사용 또는 절전 옵션을 사용해도 제공할 수 있습니다. 포그라운드에서 실행되고 실시간 위치 업데이트가 필요한 앱(예: 매핑 앱)에만 높은 정확성을 사용해야 합니다.

빈도

위치 빈도는 두 가지 메서드로 지정할 수 있습니다.

  • setinterval() 메서드를 사용하여 앱을 위해 위치를 연산하는 간격을 지정합니다.
  • setFastestInterval()을 사용하여 다른 앱에서 연산된 위치를 수신하는 간격을 지정합니다.

setInterval()을 사용할 때는 최대한 큰 값을 전달해야 합니다. 이는 특히 백그라운드 위치 수집에 중요한데, 원치 않게 배터리 소모를 일으키는 원인이 되는 경우가 많습니다. 포그라운드 사용 사례에 몇 초 간격을 사용해야 합니다. Android 8.0에 도입된 백그라운드 위치 제한은 이러한 전략을 적용하지만, Android 7.0 이하 기기에도 이 전략을 적용하고자 노력해야 합니다.

지연 시간

setMaxWaitTime() 메서드를 사용하여 지연 시간을 지정할 수 있습니다. 일반적으로 setInterval() 메서드에 지정된 간격보다 몇 배 큰 값을 전달합니다. 이 설정은 위치 정보 전달을 지연하고 여러 위치 업데이트를 일괄 전달할 수 있습니다. 이 두 가지 변경사항은 배터리 소모를 최소화하는 데 도움이 됩니다.

앱에 위치 업데이트가 즉시 필요하지 않은 경우 setMaxWaitTime() 메서드에 최대한 큰 값을 전달하여 지연 시간을 늘리는 대신 더 많은 데이터를 제공하고 배터리 효율을 높여야 합니다.

지오펜싱을 사용할 경우 앱은 setNotificationResponsiveness() 메서드에 큰 값을 전달하여 전력을 절약해야 합니다. 5분 이상의 값을 사용하는 것이 좋습니다.

위치 사용 사례

이 섹션에서는 일반적인 위치 수집 시나리오를 설명하고 Geofencing 및 Fused Location Provider API를 최적으로 사용하는 방법을 추천합니다.

사용자에게 표시되는 업데이트 또는 포그라운드 업데이트

예: 지연 시간이 매우 적으면서 자주 정확하게 업데이트를 해야 하는 매핑 앱. 모든 업데이트가 포그라운드에서 발생합니다. 사용자가 활동을 시작하면 위치 데이터가 사용되고 잠시 후 활동이 중지됩니다.

PRIORITY_HIGH_ACCURACY 또는 PRIORITY_BALANCED_POWER_ACCURACY 값이 있는 setPriority() 메서드를 사용합니다.

setInterval() 메서드에 지정되는 간격은 사용 사례에 따라 달라집니다. 실시간 시나리오의 경우, 이 값은 몇 초로 설정하고 그 외 나머지 경우에는 몇 분으로 설정합니다(배터리 사용량을 최소화하려면 약 2분 이상으로 설정하는 것이 좋습니다).

기기의 위치 확인

예: 날씨 앱이 기기의 위치를 알고자 합니다.

getLastLocation() 메서드를 사용하면 가장 최근에 수집한 위치 정보를 반환합니다(매우 드물게 null이 될 수도 있습니다). 이 메서드는 간단하게 위치 정보를 얻는 수단을 제공하고 적극적으로 위치 업데이트를 요청하는 것과 관련된 비용이 발생하지 않습니다. isLocationAvailable() 메서드와 함께 사용합니다. getLastLocation()이 반환한 위치가 적절히 최신 상태이면 true를 반환합니다.

사용자가 특정 위치에 있을 때 업데이트 시작

예: 사용자가 직장, 집 또는 다른 위치에서 특정 거리 내에 있을 때 업데이트를 요청합니다.

통합 위치 정보 제공자 업데이트와 함께 지오펜싱을 사용합니다. 앱이 지오펜싱 진입 트리거를 수신하면 업데이트를 요청하고 앱이 지오펜싱 퇴장 트리거를 수신하면 업데이트를 삭제합니다. 이렇게 하면 사용자가 지정된 영역에 들어갈 때만 앱이 더욱 자세한 위치 업데이트를 받을 수 있습니다.

이 시나리오의 일반적인 워크플로는 지오펜싱 진입 시 알림을 띄우고, 사용자가 알림을 탭할 때 업데이트를 요청하는 코드가 포함된 활동을 실행하는 것입니다.

사용자 활동 상태에 따라 업데이트 시작

예: 사용자가 운전 중이거나 자전거를 타고 있을 때만 업데이트를 요청합니다.

통합 위치 정보 제공자 업데이트와 함께 Activity Recognition API를 사용합니다. 타겟팅된 활동이 감지될 때 업데이트를 요청하고 사용자가 활동의 실행을 중지할 때 업데이트를 삭제합니다.

이 사용 사례의 일반적인 워크플로는 활동 감지 시 알림을 띄우고, 사용자가 알림을 탭할 때 업데이트를 요청하는 코드가 포함된 활동을 실행하는 것입니다.

지역과 연결된 장기 실행 백그라운드 위치 업데이트

예: 기기가 소매업체 근처에 들어갔을 때 사용자가 알림을 받기를 원합니다.

이는 지오펜싱의 모범적인 사용 사례입니다. 이 사용 사례는 백그라운드 위치를 사용하는 것이 거의 확실하므로 addGeofences(GeofencingRequest, PendingIntent) 메서드를 사용합니다.

다음과 같은 구성 옵션을 설정해야 합니다.

  • 거주지 변경을 추적하고 있다면 setLoiteringDelay() 메서드를 사용하여 약 5분 이하의 값을 전달합니다.

  • setNotificationResponsiveness()를 사용하여 약 5분에 상응하는 값을 전달합니다. 그러나 앱의 응답이 더 지연되어도 괜찮다면 약 10분에 상응하는 값을 사용해도 됩니다.

앱은 한 번에 최대 100개의 지오펜싱만 등록할 수 있습니다. 앱에서 많은 소매업체 옵션을 추적하려는 사용 사례에서는 앱이 넓은 지오펜싱(도시 수준)을 등록하고 넓은 지오펜싱 안에 있는 매장에는 좁은 범위의 지오펜싱(도시 내 위치)을 동적으로 등록하는 것이 좋습니다. 사용자가 넓은 지오펜싱에 들어가면 좁은 범위의 지오펜싱을 추가할 수 있습니다. 사용자가 넓은 지오펜싱에서 나오면 좁은 범위의 지오펜싱을 삭제할 수 있습니다. 새로운 지역에서는 지오펜싱을 다시 등록해야 합니다.

가시적 앱 구성요소가 없는 장기 실행 백그라운드 위치 업데이트

예: 위치를 수동적으로 추적하는 앱

가능하면 배터리 소모가 거의 발생하지 않는 PRIORITY_NO_POWER 옵션이 있는 setPriority() 메서드를 사용하세요. PRIORITY_NO_POWER를 사용할 수 없다면 PRIORITY_BALANCED_POWER_ACCURACYPRIORITY_LOW_POWER를 사용하되 지속적인 백그라운드 작업에는 PRIORITY_HIGH_ACCURACY를 사용하지 마세요. 이는 이 옵션의 배터리 소모가 상당하기 때문입니다.

더 많은 위치 데이터가 필요한 경우 setFastestInterval() 메서드를 호출하여 setInterval()에 전달했던 것보다 작은 값을 전달하면 수동적으로 위치 정보를 수집할 수 있습니다. 수동적 위치 정보 수집은 PRIORITY_NO_POWER 옵션과 결합하면 다른 앱에서 연산한 위치 정보를 추가 비용 없이 기회가 있을 때마다 제공받을 수 있습니다.

setMaxWaitTime() 메서드를 사용하여 지연 시간을 추가하는 방법으로 빈도를 조절합니다. 예를 들어 setinterval() 메서드에 약 10분으로 값을 설정한다면 30~60분으로 값을 설정한 setMaxWaitTime()을 호출하는 것이 좋습니다. 이 옵션을 사용하면 앱에 위치 정보가 약 10분마다 연산되지만, 앱이 30~60분마다 활성화되어서 일부 위치 데이터를 일괄 업데이트로 제공합니다. 이 방법은 지연 시간을 적용하는 대신 더 많은 데이터를 제공하고 배터리 성능을 향상합니다.

사용자가 다른 앱과 상호작용하는 동안 높은 정확성으로 자주 업데이트

예: 사용자가 화면을 끄거나 다른 앱을 열 때도 계속 작동하는 탐색 또는 피트니스 앱

포그라운드 서비스를 사용합니다. 앱에서 사용자 대신 리소스가 많이 소모되는 작업을 실행할 가능성이 있는 경우, 사용자에게 작업이 권장사항이라는 것을 알립니다. 포그라운드 서비스는 지속적인 알림이 필요합니다. 자세한 내용은 알림 개요를 참조하세요.

위치 권장사항

이 섹션의 권장사항을 구현하면 앱의 배터리 사용량을 줄이는 데 도움이 됩니다.

위치 업데이트 삭제

불필요한 배터리 소모가 발생하는 일반적인 원인은 필요하지 않은 시점에 위치 업데이트를 삭제하지 못하는 데 있습니다. 예를 들어 활동의 onStart() 또는 onResume() 수명 주기 메서드에 requestlocationUpdates() 호출이 포함되어 있지만, onPause() 또는 onStop() 수명 주기 메서드에 그에 상응하는 removeLocationUpdates() 호출이 포함되어 있지 않을 때 불필요한 배터리 소모가 발생할 수 있습니다.

수명 주기 인식 구성요소를 사용하여 앱 활동의 수명 주기를 더 효율적으로 관리할 수 있습니다. 자세한 내용은 수명 주기 인식 구성요소로 수명 주기 처리를 참고하세요.

시간 초과 설정

배터리 소모로부터 기기를 보호하려면 위치 업데이트를 중단해야 할 시점에 적절한 시간 초과를 설정합니다. 이렇게 시간 초과를 설정하면 업데이트가 무한히 계속되지 않도록 하고, (가령 코드의 버그로 인해) 업데이트를 요청했지만 삭제되지 않은 시나리오에서 앱을 보호합니다.

통합 위치 정보 제공자 요청의 경우 setExpirationDuration()을 호출해서 시간 초과를 추가하여 이 메서드를 마지막으로 호출한 시점 이후부터의 시간을 밀리초 단위로 나타내는 매개변수를 수신합니다. setExpirationTime()을 호출해도 시간 초과를 추가할 수 있습니다. 이는 시스템이 마지막으로 부팅된 시점 이후부터의 만료 시간을 밀리초 단위로 나타내는 매개변수를 수신합니다.

지오펜싱 위치 요청에 시간 초과를 추가하려면 setExpirationDuration() 메서드를 호출합니다.

일괄 요청

포그라운드에서 실행되지 않는 모든 사용 사례는 여러 요청을 한 번에 일괄 처리합니다. setInterval() 메서드를 사용하여 위치를 연산하려는 간격을 지정할 수 있습니다. 그런 다음 setMaxWaitTime() 메서드를 사용하여 앱에 위치가 전달되는 간격을 설정합니다. setMaxWaitTime() 메서드에 전달되는 값은 setInterval() 메서드에 전달된 값의 배수여야 합니다. 예를 들어 다음과 같은 위치 요청을 고려하세요.

Kotlin

val request = LocationRequest()
request.setInterval(10 * 60 * 1000)
request.setMaxWaitTime(60 * 60 * 1000)

자바

LocationRequest request = new LocationRequest();
request.setInterval(10 * 60 * 1000);
request.setMaxWaitTime(60 * 60 * 1000);

이 경우 위치는 약 10분마다 연산되고 대략 1시간마다 약 6개의 위치 데이터 포인트가 일괄 전달됩니다. 약 10분마다 위치 업데이트를 받지만 기기는 1시간 정도에 한 번씩만 활성화되므로 배터리를 아낄 수 있습니다.

수동적 위치 업데이트 사용

백그라운드 사용 사례에서는 위치 업데이트를 제한하는 것이 좋습니다. Android 8.0은 이러한 방법을 사용하지 못하게 제한하지만, 오래된 기기에서 실행되는 앱은 최대한 백그라운드 위치 업데이트를 제한하려고 노력해야 합니다.

앱이 백그라운드에 있을 때는 다른 앱이 포그라운드에서 위치 업데이트를 수시로 요청할 가능성이 있습니다. 위치 서비스를 사용하면 앱에서 이러한 업데이트를 사용할 수 있습니다. 편의적으로 위치 데이터를 사용하는 다음과 같은 위치 요청을 고려해보세요.

Kotlin

val request = LocationRequest()
request.setInterval(15 * 60 * 1000)
request.setFastestInterval(2 * 60 * 1000)

자바

LocationRequest request = new LocationRequest();
request.setInterval(15 * 60 * 1000);
request.setFastestInterval(2 * 60 * 1000);

이전의 예에서는 앱에서 위치가 약 15분마다 연산되었습니다. 다른 앱이 위치를 요청하면 그 데이터가 최대 2분 간격으로 앱에 제공됩니다.

수동적으로 위치 정보를 사용하는 데는 배터리가 소모되지 않지만 위치 데이터를 수신할 때 리소스가 많이 소모되는 CPU 또는 I/O 작업이 트리거되는 경우에는 주의해야 합니다. 배터리 비용을 최소화하려면 setFastestInterval()에 지정된 간격이 너무 작아서는 안 됩니다.

이 페이지의 권고를 따르면 사용자 기기의 배터리 성능을 크게 개선할 수 있습니다. 사용자가 배터리를 소모하지 않는 앱을 삭제할 가능성이 적습니다.