[응용] 안드로이드 GPS 위도 경도 불러오기

쓰리원·2022년 4월 27일
1

안드로이드 지도API

목록 보기
1/12
post-thumbnail

YUmarket 팀 프로젝트를 진행하면서 실제로 구현한 GPS로 위치 받아오기 코드 부분만 따와서 작성하는 글 입니다. YUmarket 중 일부 기능에 대해서 분리해서 글을 작성할 예정입니다.

1. 주요 코드 알아보기

class MainActivity : AppCompatActivity() {
    private lateinit var locationManager: LocationManager
    private lateinit var myLocationListener: MyLocationListener
    private lateinit var binding: ActivityMainBinding

    companion object {
        val locationPermissions = arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
    }

    private val permissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            val responsePermissions = permissions.entries.filter {
                it.key in locationPermissions
            }

            if (responsePermissions.filter { it.value == true }.size == locationPermissions.size) {
                setLocationListener()
            } else {
                Toast.makeText(this, "no", Toast.LENGTH_SHORT).show()
            }
        }

    private fun getMylocation() {
        if (::locationManager.isInitialized.not()) {
            locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        }
        val isGpsEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        if (isGpsEnable) {
            permissionLauncher.launch(locationPermissions)
        }
    }

    @Suppress("MissingPermission")
    private fun setLocationListener() {
        val minTime: Long = 1500
        val minDistance = 100f

        if (::myLocationListener.isInitialized.not()) {
            myLocationListener = MyLocationListener()
        }

        with(locationManager) {
            requestLocationUpdates(
                LocationManager.GPS_PROVIDER,
                minTime, minDistance, myLocationListener
            )

            requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER,
                minTime, minDistance, myLocationListener
            )
        }
    }

    inner class MyLocationListener : LocationListener {
        override fun onLocationChanged(location: Location) {
            Toast
                .makeText(this@MainActivity, "${location.latitude}, ${location.longitude}", Toast.LENGTH_SHORT)
                .show()

            binding.locationTitleTextView.text = "${location.latitude}, ${location.longitude}"

            removeLocationListener()
        }

        private fun removeLocationListener() {
            if (::locationManager.isInitialized && ::myLocationListener.isInitialized) {
                locationManager.removeUpdates(myLocationListener)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater); // 1
        setContentView(binding.root)
        getMylocation()
    }
}

코드를 분할해서 알아보겠습니다.

companion object {
	val locationPermissions = arrayOf(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION)
}

지도 권한 설정

1) ACCESS_FINE_LOCATION : GPS와 Network를 모두 사용하여 사용자의 정확한 위치를 가져오는 권한입니다.
2) ACCESS_COARSE_LOCATION : Network만을 사용하여 사용자의 대략적인 위치를 가져오는 권한입니다.

private val permissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            val responsePermissions = permissions.entries.filter {
                it.key in locationPermissions //일치성 여부 확인.
            }

            if (responsePermissions.filter { it.value == true }.size == locationPermissions.size) {
                setLocationListener()
            } else {
                Toast.makeText(this, "no", Toast.LENGTH_SHORT).show()
            }
        }

RequestMultiplePermissions : 다중 권한을 요청하고, 승인 여부를 Map<String,Boolean>형태로 반환합니다.

companion object {
val locationPermissions = arrayOf( Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION) }

-> 에 정의한 locationPermissions의 크기(size)는 2 입니다. responsePermissions.filter를 통해서 true인 size가 2일 경우에만 setLocationListener()를 실행해서 위치값을 setting 하게 됩니다.

    @Suppress("MissingPermission")
    private fun setLocationListener() {
        val minTime: Long = 1500
        val minDistance = 100f

        if (::myLocationListener.isInitialized.not()) {
            myLocationListener = MyLocationListener()
        }

        with(locationManager) {
            requestLocationUpdates(
                LocationManager.GPS_PROVIDER,
                minTime, minDistance, myLocationListener
            )

            requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER,
                minTime, minDistance, myLocationListener
            )
        }
    }

LocationManager를 통해 GPS, Network의 위치 정보를 얻을 수 있습니다.

위치 정보를 얻는 방법은 LocationManager.getLastKnownLocation()으로 가장 마지막에 기록된 위치 정보를 가져오거나 LocationManager.requestLocationUpdates()으로 Listener를 등록하여 위치가 변경될 때마다 이벤트를 받을 수 있습니다.

LocationManager의 requestLocationUpdates ( ) 함수로 LocationListener를 등록하는데, 매개변수로는 이용할 위치 정보 제공자, LocationListener 호출 주기, 그리고 변경 위치 거리의 정보를 주면 됩니다. 위의 코드는 지정된 위치 정보 제공자를 이용하여 15초마다 100미터 변경될 때마다 listener 객체의 함수를 호출하게 됩니다.

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
//provider의 상태가 변경되때마다 호출
}
@Override
public void onProviderEnabled(String provider) {
//provider가 사용 가능한 상태가 되는 순간 호출
}
@Override
public void onProviderDisabled(String provider) {
//provider가 사용 불가능 상황이 되는 순간 호출
}
@Override
public void onLocationChanged(Location location) {
//위치 정보 전달 목적으로 호출
}
};
    inner class MyLocationListener : LocationListener {
        override fun onLocationChanged(location: Location) {
            Toast.makeText(this@MainActivity, "${location.latitude}, ${location.longitude}", Toast.LENGTH_SHORT)
                .show()

            binding.locationTitleTextView.text = "${location.latitude}, ${location.longitude}"

            removeLocationListener()
        }

        private fun removeLocationListener() {
            if (::locationManager.isInitialized && ::myLocationListener.isInitialized) {
                locationManager.removeUpdates(myLocationListener)
            }
        }
    }

fun removeLocationListener()로 Listener를 한번 사용해주고 사용하지 않을 때는 해지해줍니다.

private fun getMylocation() {
        if (::locationManager.isInitialized.not()) {
            locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager 
            //로케이션 객체 선언.
        }
        val isGpsEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
		//GPS사용 가능여부 확인.
        if (isGpsEnable) {//Gps사용 가능하다면
			permissionLauncher.launch(locationPermissions)
        }
    }

getMylocation()에도 세부적으로 보아야할 fuc들이 있습니다. 차근히 뜯어서 알아보겠습니다.

locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager 

LocationManager는 시스템 서비스로 getSystemService() 메서드로 얻어서 사용합니다.

locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)

LocationManager의 메서드를 이용하여 위치 정보를 가져올 수 있습니다. locationManager.isProviderEnabled로 사용 가능 여부를 체크합니다.

GPS : GPS 위성을 이용하여 위치 정보 획득
Network : 이동통신사 망 정보를 이용하여 위치 정보 획득
Wifi : 와이파이의를 이용하여 위치 정보 획득
Passive : 다른 앱에서 이용한 마지막 위치 정보 획득

if (isGpsEnable) {//Gps사용 가능하다면
	permissionLauncher.launch(locationPermissions)
}

permissionLauncher.launch(locationPermissions)를 실행해서 내 위치를 받아옵니다.

구현 코드 주소 : https://github.com/ilil1/locationGPS

2. reference

https://developer.android.com/training/location/request-updates?hl=ko
https://developer.android.google.cn/about/versions/12/approximate-location?hl=ko
https://developer.android.com/training/location/permissions?hl=ko

profile
가장 아름다운 정답은 서로의 협업안에 있다.

0개의 댓글