LocationManager를 이용하여 현재 내 위치를 구현할 것이다.
LocationManager를 쓰는게 여러가지를 두고 봤을 때 가장 간단해서 쓰는 것이다.
위 사진과 같이 임장노트를 작성할 때 대략적인 나의 위치를 미리 매핑해주는 역할을 한다. 그렇게 되면, 세부적인 주소만 작성하고 나머지 주소는 따로 타이핑 하지 않아도 되서 간편할 것이다.
과정은 간단하게 아래에 순서대로 서술하겠다.
- AndroidManifest에 ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION 권한을 추가해준다.
- 해당 권한을 사용할 수 있게 PermissionListener를 만든다. (tedPermission강력 추천)
- MyLocation 클래스를 만들어준다. 이때 파라미터에 Activity Context를 넣어준다. LocationManager를 Activity Context의 만들어주는 이유는, Activity가 onDestroy 됐을 때 GC가 메모리를 알아서 처리해주기 때문이다.
- 내 현재 위치를 반환해주는 get 함수를 만든다.
이제 위 과정들을 한번 구현해보자.
1. useMyLocation.kt
view에 해당하는 클래스이다. Permission이 주제인 포스팅은 아니니까 Permission에 대한 것은 간단하게 view에서 만들어주고 ViewModel에 있는 내 위치 가져오는 메소드만 불러줄 것이다.
class UseMyLocation:BaseActivity(){
...
private fun permissionCheck() {
if (viewModel.checkCoarseLocationPermission(this@WriteAuctionActivity) &&
viewModel.checkFineLocationPermission(this@WriteAuctionActivity)
) {
tedPermission()
} else {
viewModel.getLocation(this@WriteAuctionActivity)
}
}
private fun tedPermission() {
val permissionListener = object : PermissionListener {
override fun onPermissionGranted() {
viewModel.getLocation(this@WriteAuctionActivity)
}
override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
Toast.makeText(
this@WriteAuctionActivity,
"설정에서 권한을 허가 해주세요.",
Toast.LENGTH_SHORT
).show()
}
}
TedPermission.with(this)
.setPermissionListener(permissionListener)
.setRationaleMessage("서비스 사용을 위해서 몇가지 권한이 필요합니다.")
.setDeniedMessage("[설정] > [권한] 에서 권한을 설정할 수 있습니다.")
.setPermissions(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
.check()
}
}
2. UseMyLocationViewModel.kt
ViewModel에서는 MyLocation 클래스를 통하여 주소를 불러와 myLocation 변수에 주소를 넣어줄 것이다 .이때 myLocation 변수는 ObservableField<String> 타입으로 지정하여 값이 변하면 자동으로 값이 TextView에 반영되게 해 두었다.
@HiltViewModel
class UseMyLocationViewModel @Inject constructor() : ViewModel() {
val myLocation: ObservableField<String> = ObservableField("주소를 표시할 수 없습니다.")
fun checkFineLocationPermission(context: Context): Boolean = ActivityCompat.checkSelfPermission(
context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
fun checkCoarseLocationPermission(context: Context): Boolean =
ActivityCompat.checkSelfPermission(
context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
@SuppressLint("MissingPermission")
fun getLocation(context: Context) {
val locationLoader = MyLocation(context)
myLocation.set(locationLoader.get())
}
}
3. Mylocation.kt
실질적으로 이곳에서 현재 내 위치를 받아오는 곳이다.
class MyLocation constructor(private val context: Context) {
private lateinit var locationManager: LocationManager
fun get(): String {
setLocationManager()
return setMyLocation(getLastLocation())
}
private fun setLocationManager() {
// locationManager 초기화 해주기
locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
}
/*
Permission은 MyLocation 클래스가 아니라 해당 클래스를 사용해주는
클래스에서 처리해주기
따라서 MissingPermission을 Supress 해준다.
*/
@SuppressLint("MissingPermission")
private fun getLastLocation(): Location? =
if (locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) != null) {
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
} else {
locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
}
// loc 변수에서 latitude, longtitude 추출
private fun setMyLocation(loc: Location?): String {
return if (loc != null) {
val latlng = LatLng(loc.latitude, loc.longitude)
return getAddress(latlng)
} else {
"주소정보 가져올 수 없음"
}
}
// Geocoder를 자기 나라에 맞게 설정해준다.
// try catch 문으로 grpc 오류 대처해주기
private fun getAddress(position: LatLng): String {
val geoCoder = Geocoder(context, Locale.KOREA)
var addr = "주소 오류"
try {
addr = geoCoder.getFromLocation(position.latitude, position.longitude, 1).first()
.getAddressLine(0)
} catch (e: Exception) {
e.printStackTrace()
}
return addr
}
}
앞서 설명한 과정을 코딩하면 위와 같은 코드가 나온다.
이때 무조건적으로 조심해야 할 것이 있다. 바로 GRPC 오류이다. 이 grpc 오류는 getCoder를 사용할때 주로 생기며, 발생 원인은 앱 에뮬레이터의 네트워크가 불안정하면, 주소를 제대로 가져올 수 없어서 해당 오류가 발생하게 된다.
따라서 geoCoder를 사용할때는 try~catch문을 이용해서 오류에 대한 대처를 해주는게 가장 현명하다.
참고
https://angangmoddi.tistory.com/227
'안드로이드 > 프로젝트' 카테고리의 다른 글
[안드로이드] 임장노트 #1 프로젝트 구상하기 (0) | 2021.12.07 |
---|