[Andorid] 산책 앱 개발 일지 2: 사용자 위치 추적하기

클로이·2021년 12월 22일
0

왜 사용자 위치를 추적해요?

  • 사용자가 걷거나 운전하는 동안 길을 찾아주는 앱 또는 사용자의 위치를 추적하는 앱은 일정한 간격으로 기기의 위치를 파악해야해요.

이 앱에서는 사용자가 산책을 할 때 위치를 추적할거에요.


위치 권한 설정

AndroidManifest.xml

<manifest ... >
  
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
  ...
</manifest>

위치 서비스 클라이언트 만들기

  • 위치를 추적하기 위한 인스턴스를 만들어요.

TrackingService.kt

class TrackingService: LifecycleService() {
    lateinit var fusedLocationProviderClient: FusedLocationProviderClient
    
    //...
    
    override fun onCreate() {
        super.onCreate()

        //...

        fusedLocationProviderClient = getFusedLocationProviderClient(this)

        //...
    } 

위치 요청에 필요한 설정 제공하기

  • 앱에서 위치를 요청하거나 권한 업데이트 수신에 필요한 시스템 설정을 LocationRequest 데이터 객체에서 정의해요.
  • interval은 위치 요청에 필요한 수신 간격이에요.
  • fastestInterval은 위치 요청에 필요한 가장 빠른 수신 간격이에요.
  • priority는 위치 요청에 필요한 정확도를 설정해요.

이 앱에서는 가장 정확한 위치를 요청하는 PRIORITY_HIGH_ACCURACY를 설정했어요.

TrackingService.kt

@SuppressLint("MissingPermission")
    private fun updateLocationChecking(isTracking: Boolean) {
        if (isTracking) {
            if (TrackingUtility.hasLocationPermissions(this)) {

                val locationRequest = LocationRequest.create().apply {
                    interval = LOCATION_UPDATE_INTERVAL
                    fastestInterval = FASTEST_LOCATION_INTERVAL
                    priority = PRIORITY_HIGH_ACCURACY
                }

                //...

            }
        } else {

            //...
        }
    }            

위치 요청하기

  • 위도 및 경도LocationCallback.onLocationResult() 콜백 메서드에 포함되어 있는 Location 객체로 얻어올 수 있어요.

TrackingService.kt

val locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            super.onLocationResult(locationResult)
            if (isTracking.value!!) {
                locationResult?.locations?.let {
                    for (location in it) {
                        // Update UI with location data
                    }
                }
            }
        }
    }

위치 갱신하기 / 중지하기

  • 위치를 요청한 후 requestLocationUpdates()로 갱신 되는 위치를 확인할 수 있어요.
  • removeLocationUpdates로 위치 갱신을 중지할 수 있어요.

이 앱에서는 사용자가 산책 시작 버튼을 눌렀을 때 위치를 갱신하고 산책 끝 버튼을 눌렀을 때 위치 요청을 중지해요.

TrackingService.kt

@SuppressLint("MissingPermission")
    private fun updateLocationTracking(isTracking: Boolean) {
        if (isTracking) {
            if (TrackingUtility.hasLocationPermissions(this)) {

                //...

                fusedLocationProviderClient.requestLocationUpdates(
                    locationRequest,
                    locationCallback,
                    Looper.getMainLooper()
                )

            }
        } else {

            	fusedLocationProviderClient.removeLocationUpdates(locationCallback)
        }
    }

위치 권한 요청하기

build.gradle (:app)

  • easypermissions 라이브러리를 사용했어요.
dependencies {
	implementation 'com.vmadalin:easypermissions-ktx:1.0.0'
}

TrackingUtility.kt

  • object로 싱글턴 클래스를 정의해서 위치 권한 확인 함수를 생성했어요.
fun hasLocationPermissions(context: Context) =
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            EasyPermissions.hasPermissions(
                context,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION
            )
        } else {
            EasyPermissions.hasPermissions(
                context,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION
            )
        }

TrackingFragment.kt

  • 산책 시작 버튼을 눌렀을 때 위치 권한을 확인해요.
class TrackingFragment : Fragment(R.layout.fragment_tracking), EasyPermissions.PermissionCallbacks  {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
   //...
   
        binding.btnStart.setOnClickListener {
            if(TrackingUtility.hasLocationPermissions(requireContext())){
                sendCommandToService(ACTION_START_OR_RESUME_SERVICE)
            }else {
                requestPermissions()
            }
        }
        
        //...
        
    }

// ...

private fun requestPermissions() {
        if (TrackingUtility.hasLocationPermissions(requireContext())) { // 권한이 있는 경우에는 권한을 요청하지 않습니다.
            return
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            EasyPermissions.requestPermissions(
                this,
                "'어야가자' 이용을 위해 위치 권한을 '허용'으로 선택해주세요.",
                Constants.REQUEST_CODE_LOCATION_PERMISSION,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION
            )
        } else {
            EasyPermissions.requestPermissions(
                this,
                "'어야가자' 이용을 위해 위치 권한을 '허용'으로 선택해주세요.",
                Constants.REQUEST_CODE_LOCATION_PERMISSION,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION
            )
        }
    }
    
    override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
        TODO("Not yet implemented")
    }

    override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            AppSettingsDialog.Builder(this).build().show()
        } else {
            requestPermissions()
        }
    }
}

UI 업데이트를 위한 변수(trackingLocation) 생성

이 앱에서는 UI 업데이트를 위한 데이터를 관찰하여 위치를 표시할거에요.

TrackingService.kt

companion object {
        //...
        
        val trackingLocation = MutableLiveData<LatLng>()
    }
    
    //...
    
    val locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            super.onLocationResult(locationResult)
            if (isTracking.value!!) {
                locationResult?.locations?.let {
                    for (location in it) {
                        var locationUpdate = LatLng(location.latitude!!, location.longitude!!)
                        trackingLocation.postValue(locationUpdate)
                    }
                }
            }
        }
    }

TrackingFragment.kt

private fun subscribeToObservers() {
        //...

        TrackingService.trackingLocation.observe(viewLifecycleOwner, { trackingLocation ->
            map?.animateCamera(CameraUpdateFactory.newLatLngZoom(trackingLocation, MAP_ZOOM))
        })
    }

참고&출처

마지막으로 알려진 위치 가져오기
위치 설정 변경
위치 업데이트 요청
Tracking User Location in the Background - MVVM Running Tracker App - Part 13

0개의 댓글