개발하는 두더지

[Android/Kotlin] FusedLocationProvider를 이용한 기기의 현재위치 가져오기 본문

Kotlin

[Android/Kotlin] FusedLocationProvider를 이용한 기기의 현재위치 가져오기

덜지 2018. 12. 11. 20:15

간단하고, 배터리 효율적인 위치 API


앱은 기기의 여러 센서가 제공하는 신호를 활용하여 기기 위치를 파악할 수 있습니다. 그러나 여러 환경에서 적합한 신호 조합을 선택하는 것은 쉽지 않습니다. 배터리 효율적인 방법을 찾는 것 또한 복잡합니다.  FusedLocationProvider 는 위치 정보를 제공하기 위해 여러 신호를 지능적으로 조합하는 Google Play Service에서 제공하는 위치 API 입니다.


코드로 살펴보겠습니다. 

build.gradle 에 구글 플레이 서비스에서 제공하는 API를 주입시켜줍니다.  

// google map api & location
implementation 'com.google.android.gms:play-services-maps:16.0.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'


AndroidManifest.xml에 다음의 퍼미션을 추가해줍니다.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />


Sync Projects를 완료하고나면 원하는 곳에 위치 API를 사용할 수 있습니다.

MainActivity 에 현재 위치를 가져오는 방법입니다. checkSelfPermission을 통해 ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION 권한이 있는지 런타임에 확인해주고 권한이 있으면 위치 서비스에 연결시켜주고 lastLocation을 통해 현재위치를 가져올 수 있습니다.

private fun initLocation() {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}

fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
fusedLocationClient.lastLocation
.addOnSuccessListener { location ->
if(location == null) {
Log.e(TAG, "location get fail")
} else {
Log.d(TAG, "${location.latitude} , ${location.longitude}")
}
}
.addOnFailureListener {
Log.e(TAG, "location error is ${it.message}")
it.printStackTrace()
}
}


location이 null이 올 수 있는 상황이 있습니다

  • 기기 설정에서 위치를 비활성화 시키면 결과는 null이 나올 수 있습니다. 위치를 비활성화하면 캐시까지 지워지기 때문에 이전에 얻은 마지막 위치일지라도 구할 수 없게됩니다.

  • 위치 권한을 한번 비활성화 시키고 다시 활성화시켜도 앱에서 바로 위치정보를 가져올 수 없습니다. 그래서 위치 업데이트를 요청을 해야 합니다. 



아래와 같이 위치정보를 요청합니다.
locationRequest = LocationRequest.create()
locationRequest.run {
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
interval = 60 * 1000
}

locationCallback = object: LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult?.let {
for((i, location) in it.locations.withIndex()) {
Log.d(TAG, "#$i ${location.latitude} , ${location.longitude}")
}
}
}
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
위치서비스에 데이터를 요청할 객체를 생성하고 정확도와 인터벌 시간을 정해줍니다. 그리고 위치 데이터를 받을 콜백을 만들어주고 FusedLocationProvider로 위치 데이터를 요청합니다.  위치 정보를 요청하고 처리하는 작업은 배터리 소모가 큰 작업이므로 화면이 보이는 시점인 onResume에서 작업하고 화면이 사라지는 시점인 onPause에서 콜백 리스너를 해제해야 합니다. 

override fun onPause() {
super.onPause()
fusedLocationClient.removeLocationUpdates(locationCallback)
}
requestLocationUpdatesinterval 마다 계속 현재 위치 데이터를 요청하므로 현재 위치를 주기적으로 체크하는 케이스에 알맞습니다. 예를들어 걷기, 런닝시에 위치정보를 기록하는 경우입니다.

위의 API들을 적절하게 사용하여 위치정보를 얻어서 사용하시면 됩니다.



Comments