안드로이드/안드로이드
[안드로이드] Service에서 위치 데이터 지속적으로 얻기
snaildeveloper
2025. 5. 8. 11:12
Service를 이용하여 백그라운드에서 실시간 위치 데이터를 지속적으로 얻어오는 방법입니다.
1. 실시간 위치 데이터
실시간 위치 데이터는 FusedLocationProviderClient를 이용하여 쉽게 얻을 수 있다.
val mFusedLocationClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(context)
다음과 같이 FusedLocationProviderClient를 초기화하고 이를 통해 위치 데이터를 얻을 수 있다.
마지막 위치
val lastLocation: Task<Location> = mFusedLocationClient.lastLocation
지속적인 위치
mFusedLocationClient.requestLocationUpdates(
LocationRequest,
LocationCallback,
Looper
)
지속적인 위치의 경우 requestLocationUpdates()를 통해 얻을 수 있으며, 해당 메서드에는 3가지 인자를 필요로 한다.
LocationRequest
val locationRequestBuilder = LocationRequest.Builder(
PRIORITY_BALANCED_POWER_ACCURACY, // priority, 생략 가능
5_000L // intervalMillis, 필수
)
val locationRequest = locationRequestBuilder.build()
Builder에서 다양한 설정을 할 수 있다.
- setIntervalMillis: Builder를 생성할 때 초기화하는 속성으로, 위치 업데이트 간격을 지정한다.
- setPriority: Builder를 생성할 때 초기화 할 수 있으며, 아래와 같은 속성을 설정한다.
- PRIORITY_BALANCED_POWER_ACCURACY: 기본 값으로, 위치의 정확도와 전력 사용의 균형을 이룬다.
- PRIORITY_HIGH_ACCURACY: 전력을 추가로 사용하더라도 높은 정확도를 선호한다.
- PRIORITY_LOW_POWER: 낮은 전력을 선호하며, 이로 인해 정확도가 다소 떨어질 수 있다.
- PRIORITY_PASSIVE: 위치를 가져오는데 추가 전력을 소모하지 않는다.
- 이외의 다양한 속성은 여기!
LocationCallback
val locationCallback =
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val lastLocation = locationResult.lastLocation!!
val latitude = lastLocation.latitude
val longitude = lastLocation.longitude
// TODO TASK
}
}
위치가 업데이트 될 때마다 실행되는 인터페이스
Looper
현재 스레드(메인 스레드) 의 루퍼 전달
- Looper.myLooper()
- Looper.getMainLooper()
따로 스레드 관리를 하지 않은 이상 두 메서드 모두 동일한 Looper를 반환한다.
전체 코드
fun initLocationUpdate(){
val mFusedLocationClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(context)
val mLocationRequestHighAccuracy = LocationRequest.Builder(PRIORITY_HIGH_ACCURACY, 5_000L)
val locationCallback =
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val lastLocation = locationResult.lastLocation!!
val latitude = lastLocation.latitude
val longitude = lastLocation.longitude
// TODO TASK
}
}
mFusedLocationClient.requestLocationUpdates(
mLocationRequestHighAccuracy,
locationCallback,
Looper.myLooper()
)
}
2. Service에 적용
Service에 필요한 foreground와 notification에 대한 설명은 생략하겠습니다.
class LocationService: Service() {
private lateinit var notificationManager: NotificationManager
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
createNotificationChannel() // 채널 생성
startForeground(101, getNotification())
initLocationUpdate()
return START_STICKY
}
private fun createNotificationChannel() {
notificationManager =
getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW // 알림 시 진동 없음
)
notificationManager.createNotificationChannel(channel)
}
private fun getNotification(): Notification {
val builder: NotificationCompat.Builder =
NotificationCompat.Builder(applicationContext, CHANNEL_ID)
builder
.setContentTitle("Title")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSmallIcon(R.drawable.ic_launcher_background)
return builder.build()
}
private fun initLocationUpdate(){
val mFusedLocationClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(context)
val mLocationRequestHighAccuracy = LocationRequest.Builder(PRIORITY_HIGH_ACCURACY, 5_000L)
val locationCallback =
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val lastLocation = locationResult.lastLocation!!
val latitude = lastLocation.latitude
val longitude = lastLocation.longitude
// TODO TASK
}
}
mFusedLocationClient.requestLocationUpdates(
mLocationRequestHighAccuracy,
locationCallback,
Looper.myLooper()
)
}
companion object {
private const val CHANNEL_ID = "BackgroundLocationUpdateService"
private const val CHANNEL_NAME = "BackgroundLocationUpdateService"
}
}
Manifest 등록
<application
...>
<service
android:name=".LocationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location"/>
</application>
Manifest에서 foregroundServiceType을 lcoation으로 지정해주지 않으면 앱을 닫았을 때 백그라운드에서 Service가 동작하고 있지만 실시간 위치를 받지 못하게 된다.
따라서 앱을 닫았을 때에도 실시간 위치를 얻고 싶은 경우에는 반드시 foregroundServiceType을 location으로 지정해주어야 한다.
Service 시작
val intent = Intent(context, LocationService::class.java)
startService(intent)