ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Android Fused Location
    Android/LBS 2019. 7. 26. 17:56

    유저 디바이스의 위치를 획득하기 위해서는 API는 표준 라이브러리에 있는 LocationManager를 이용하여 LocationProvider 지정을 통해 getLastKnownLocation 함수를 이용해서 위치 획득이 가능하다.

    하지만 LocationProvider를 지정하는 부분이 실제 작업 시 여러 가지를 고려하다 보니 개발자 코드 양이 비대해진다.

     

    이런 작업을 쉽게 하기 위해 Google Play Service에서 제공하는 Fused Location을 사용하면 된다.

     

    Fused Location의 목적은

    • Reduce Power ( 저전력 ) 
    • Improve accuracy ( 정확도 향상 )
    • Simplify the APIs ( API 간소화 )
    • Expose cool new features ( 새로운 기능 )
    • and make it available on most Android devices  ( Android 기기의 범용화 )

    휴대폰에서 활용되는 기존 Location Provider의 종류와 각 Provider의 특징을 살펴보자면 ( 숫자가 높을수록 나쁨 )

      GPS  WIFI  CELL  SENSORS 
    배터리 소모율 3 2 1 2
    정확성 1 2 3 2
    범위  3 2 1 1

    Gradle Dependency

     

    implementation 'com.google.android.gms:play-services-location:17.0.0'


    1. 필수 인터페이스 상속받기

     

    GoogleApiClient.ConnectionCallbacks : 위치 정보 제공자가 사용여부에 따른 인터페이스
    GoogleApiClient.OnConnectionFailedListener : 위치 정보 제공자 흭득 실패 인터페이스

    class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {
    
        @RequiresApi(Build.VERSION_CODES.P)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            TedPermission.with(this)
                .setPermissionListener(permissionListener)
                .setRationaleConfirmText("권한 필요")
                .setDeniedMessage("권한 거절")
                .setPermissions(Manifest.permission.ACCESS_FINE_LOCATION)
                .check()
        }
    
        /**
         * 위치 정보 제공자가 사용 가능 상태가 되었을때 호출
         */
        override fun onConnected(bundle: Bundle?) {
        }
    
        /**
         * 함수와 사용 불가능 상태가 되었을 때 호출
         */
        override fun onConnectionSuspended(p0: Int) {
        }
    
        /**
         * 위치 정보 제공자를 얻지 못할때 호출
         */
        override fun onConnectionFailed(p0: ConnectionResult) {
        }
    
        private val permissionListener = object : PermissionListener {
            override fun onPermissionGranted() {
                Toast.makeText(this@MainActivity, "권한 허가", Toast.LENGTH_SHORT).show()
            }
    
            override fun onPermissionDenied(deniedPermissions: ArrayList<String>?) {
                Toast.makeText(this@MainActivity, "권한 거부", Toast.LENGTH_SHORT).show()
            }
        }
    
    }
    

    2. 필요 객체 생성

    class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {
    
        lateinit var providerClient: FusedLocationProviderClient
        lateinit var googleApiClient: GoogleApiClient
    
        @RequiresApi(Build.VERSION_CODES.P)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            TedPermission.with(this)
                .setPermissionListener(permissionListener)
                .setRationaleConfirmText("권한 필요")
                .setDeniedMessage("권한 거절")
                .setPermissions(Manifest.permission.ACCESS_FINE_LOCATION)
                .check()
    
            googleApiClient = GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build()
    
            providerClient = LocationServices.getFusedLocationProviderClient(this)
    
            googleApiClient.connect()
    
        }
    
        /**
         * 위치 정보 제공자가 사용 가능 상태가 되었을때 호출
         */
        override fun onConnected(bundle: Bundle?) {
        }
    
        /**
         * 함수와 사용 불가능 상태가 되었을 때 호출
         */
        override fun onConnectionSuspended(p0: Int) {
        }
    
        /**
         * 위치 정보 제공자를 얻지 못할때 호출
         */
        override fun onConnectionFailed(p0: ConnectionResult) {
        }
    
        private val permissionListener = object : PermissionListener {
            override fun onPermissionGranted() {
                Toast.makeText(this@MainActivity, "권한 허가", Toast.LENGTH_SHORT).show()
            }
    
            override fun onPermissionDenied(deniedPermissions: ArrayList<String>?) {
                Toast.makeText(this@MainActivity, "권한 거부", Toast.LENGTH_SHORT).show()
            }
        }
    
    }
    

    3. 필요 정보 추출

        /**
         * 위치 정보 제공자가 사용 가능 상태가 되었을때 호출
         */
        override fun onConnected(bundle: Bundle?) {
            providerClient.lastLocation.addOnSuccessListener {
                it?.let {
                    "위도 : ${it.latitude} 경도 : ${it.longitude}".log()
                }
            }
        }

    4. 결과

    위도 : 37.5602866 경도 : 126.9728302

    실제 앞서 소개한 LocationManager와 비교 하였을때, 실제 프로젝트에서 사용해본적은 없어 차이는 느끼지 못하지만 좀더 인터페이스의 함수들이 명확하다고 해야하나? 애매한느낌은 없어진거 같다는 생각이 든다.

     

    위의 코드상으로는 최초 1회만 좌표를 불러오지만 지속적으로 위치 획득하기 위해서는 LocationListener와 LocationRequest 필요하다


    5. 지속적인 좌표값 얻어오기

        val listener = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult?) {
                locationResult?.let {
                    "위도 : ${it.lastLocation.latitude} 경도 : ${it.lastLocation.longitude}".log()
                }
            }
        }
    
        /**
         * 위치 정보 제공자가 사용 가능 상태가 되었을때 호출
         */
        override fun onConnected(bundle: Bundle?) {
            val locationRequest = LocationRequest.create()
            locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
            locationRequest.interval = 3000
            providerClient.requestLocationUpdates(locationRequest, listener, null)
        }
    

    기존에는 LocationServices.FusedLocationApi 방식으로 가져와 사용하였지만 deprecated가 되어서 위와 같은 방법으로 처리한다.


    6. 결과

    D: 위도 : 37.5602895 경도 : 126.9728369
    D: 위도 : 37.5603001 경도 : 126.9728374
    D: 위도 : 37.5602958 경도 : 126.972811

    댓글

Designed by Tistory.