//Manifest
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
각각 GPS, Network를 통해 위치를 받아올 수 있게 하는 Permission이다. manifest 최상단에 추가하여 권한에 접근 할 수 있도록 한다.
private lateinit var locationManager: LocationManager
private lateinit var locationListener: LocationListener
private val locationPermissionLauncher =
registerForActivityResult
(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val responsePermissions = permissions.entries.filter {
it.key == Manifest.permission.ACCESS_FINE_LOCATION ||
it.key == Manifest.permission.ACCESS_COARSE_LOCATION
}
if (responsePermissions.filter { it.value == true }.size ==
locationPermissions.size) {
setLocationListener()
} else {
if (!ActivityCompat.shouldShowRequestPermissionRationale
(requireActivity(), locationPermissions[0])
) {
showPermissionDialog()
} else {
Toast.makeText(context,
"위치 접근 권한을 받지 못했습니다.",
Toast.LENGTH_SHORT).show()
binding.errorTextView.isVisible = true
binding.progressBar.isGone = true
binding.locationTextView.isGone = true
}
}
}
location을 update하기 위한 locationManager, location이 바뀌었을 때를 감지하기 위한 locationListener를 lateinit 으로 선언하여 추후에 쓰도록 한다.
locationPermissionLauncher를 정의하여 위치 권한을 받아야 할 타이밍에 해당 런처를 launch하게 되면 위치 권한을 요청하게 된다.
요청의 결과가 요청한 permission을 모두 받아왔다면 setLocationListener 메소드를 통해 위치 변경을 감지하는 리스너를 등록해 위치 값을 update한다. 못했다면 shouldShowRequestPermissionRationale을 통해 사용자가 여러 번 앱 내에서 요청하는 Permission을 Deny하여 교육용 팝업을 띄워야 하는 상황인지 판단하고, 교육용 팝업이 필요할 시에는 showPermissionDialog 메소드를 통해 구현한 AlertDialog를 통해 권한을 직접 설정할 수 있도록 유도한다.
AlertDialog에서 확인을 누르면 intent action을 통해 설정 창으로 유저를 이동하게 할 수 있다.
사용자가 여러번 권한을 Deny 하여 교육용 팝업이 뜨게 될 때에는 개발자 입장에서 설정 창으로 이동시키는 것이 최선이다.
private fun getMyLocation() {
binding.progressBar.isVisible = true
binding.locationTextView.isGone = true
binding.errorTextView.isGone = true
if (::locationManager.isInitialized.not()) {
locationManager =
requireActivity().getSystemService(Context.LOCATION_SERVICE)
as LocationManager
}
val isGpsEnable = locationManager.
isProviderEnabled(LocationManager.GPS_PROVIDER)
val isNetworkEnable = locationManager.
isProviderEnabled(LocationManager.NETWORK_PROVIDER)
if (isGpsEnable || isNetworkEnable) {
locationPermissionLauncher.launch(locationPermissions)
}
}
getMyLocation 메소드를 구현하여 initViews 메소드에서 호출한다.
locationManager를 정의하고 gps, network provider가 enable 된 상태라면 locationPermissionLauncher를 launch하여 권한을 요청한다.
private fun setLocationListener() {
val minTime: Long = 1500
val minDistance = 100f
if (!::locationListener.isInitialized) {
locationListener = this
}
with(locationManager) {
requestLocationUpdates(
LocationManager.GPS_PROVIDER,
minTime, minDistance, locationListener
)
// requestLocationUpdates(
// LocationManager.NETWORK_PROVIDER,
// minTime, minDistance, locationListener
// )
}
}
override fun onLocationChanged(location: Location) {
...
}
setLocationListener에서는 requestLocationUpdates 메소드를 통해 GPS, Network를 통한 위치 값을 request하여 받아오고 업데이트 한다. locationListener를 등록해 위치의 변경을 감지하도록 한다.
이후 onLocationChanged를 override하여 location 값을 받아오고, block 내에서 얻어온(변경된) location 값을 기반으로 로직을 구현한다. (onLocationChanged 메소드를 override 하기 위해서는 LocationListener를 상속 받아야 하며, locationListener = this를 통해 리스너를 상속받은 Activity 또는 Fragment와 연결한다.)
* requestLocationUpdates 메소드는 주석처리 되어 있는데, 에뮬레이터에서는 network provider가 제대로 동작하지 않아 주석처리 해 놓았다. 실제 앱에서는 gps, network를 둘 다 요청하여 먼저 오는 값을 받도록 한다. 각각 실내, 실외에서 위치를 잘 감지하기 때문에 둘 다 사용하는 것이 좋다.
Github : https://github.com/HunSeongPark/Coroga
'Android' 카테고리의 다른 글
[Android, Kotlin] Gradle / build.gradle(project)와 build.gradle(module) 차이 (0) | 2021.11.12 |
---|---|
[Android, Kotlin] Recycler View 안에 Recycler View 넣기, 중첩 RecyclerView (0) | 2021.11.11 |
[Android, Kotlin] Back Stack을 활용한 Fragment 뒤로가기 버튼 동작, Fragment 전환 애니메이션 (0) | 2021.11.11 |
[Android, Kotlin] Architecture Pattern - MVVM (0) | 2021.11.11 |
[Android, Kotlin] Architecture Pattern - MVP (0) | 2021.11.11 |