Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

안드로이드 코틀린(Kotlin)에서 위도·경도 좌표로 전체 주소 가져오는 방법

개요

이 예제는 안드로이드 코틀린에서 위도(latitude)와 경도(longitude) 값을 이용해 전체 주소를 가져오는 방법을 보여줍니다. Geocoder 클래스를 활용해 좌표를 실제 주소로 변환하는 역지오코딩(Reverse Geocoding) 기법을 사용하며, 위치 권한 처리부터 결과 표시까지 전체 과정을 단계별로 살펴봅니다.

1단계: 새 프로젝트 생성

Android Studio에서 File ⇒ New Project로 이동해 새 프로젝트를 생성하고, 프로젝트 생성에 필요한 모든 세부 정보를 입력합니다.

2단계: 레이아웃 파일 작성

res/layout/activity_main.xml에 다음 코드를 추가합니다. 주소를 표시할 버튼과 텍스트뷰를 배치합니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
   xmlns:tools="https://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:padding="16sp"
   tools:context=".MainActivity">
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_marginTop="50dp"
      android:text="Tutorials Point"
      android:textAlignment="center"
      android:textColor="@android:color/holo_green_dark"
      android:textSize="32sp"
      android:textStyle="bold" />
   <Button
      android:id="@+id/btnShowAddress"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:text="Show Address" />
   <TextView
      android:id="@+id/tvAddress"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_below="@id/btnShowAddress"
      android:layout_centerInParent="true"
      android:textColor="@android:color/background_dark"
      android:textSize="12sp"
      android:textStyle="bold" />
</RelativeLayout>

3단계: MainActivity 구현

src/MainActivity.kt에 다음 코드를 추가합니다. 이 코드는 위치 권한을 요청하고, 버튼 클릭 시 Geocoder를 통해 주소를 가져와 화면에 표시합니다.

import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.provider.Settings
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
   lateinit var btnShowAddress: Button
   lateinit var tvAddress: TextView
   lateinit var location: Location
   lateinit var appLocationService: AppLocationService
   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      title = "KotlinApp"
      tvAddress = findViewById(R.id.tvAddress)
      appLocationService = AppLocationService(this)
      btnShowAddress = findViewById(R.id.btnShowAddress)
      if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
         if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1);
         } else {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1);
         }
      }
      btnShowAddress.setOnClickListener {
         location = appLocationService.getLocation(LocationManager.GPS_PROVIDER)!!
         val latitude = 13.1000727
         val longitude = 80.2126274
         val locationAddress = LocationAddress()
         locationAddress.getAddressFromLocation(
            latitude, longitude, applicationContext, GeoCodeHandler()
         )
         showSettingsAlert()
      }
   }
   private fun showSettingsAlert() {
      val alertDialog = AlertDialog.Builder(this)
      alertDialog.setTitle("SETTINGS")
      alertDialog.setMessage("Enable Location Provider! Go to settings menu?")
      alertDialog.setPositiveButton("Settings") { _, _ ->
         val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
         this@MainActivity.startActivity(intent)
      }
      alertDialog.setNegativeButton("Cancel") { dialog, _ -> dialog.cancel() }
      alertDialog.show()
   }
   internal inner class GeoCodeHandler : Handler() {
      override fun handleMessage(message: Message) {
         val locationAddress: String
         locationAddress = when (message.what) {
            1 -> {
               val bundle = message.data
               bundle.getString("address")
            }
            else -> null.toString()
         }
         tvAddress.text = locationAddress
      }
   }
   override fun onRequestPermissionsResult(
      requestCode: Int,
      permissions: Array<out String>,
      grantResults: IntArray
   ) {
      when (requestCode) {
         1 -> {
            if (grantResults.isNotEmpty() && grantResults[0] ===
            PackageManager.PERMISSION_GRANTED) {
               if ((ContextCompat.checkSelfPermission(
                  this@MainActivity,
                  Manifest.permission.ACCESS_FINE_LOCATION
               ) === PackageManager.PERMISSION_GRANTED)
               ) {
                  Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
               }
            } else {
               Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
            }
            return
         }
      }
   }
}

4단계: AppLocationService 클래스 생성

새로운 코틀린 클래스를 생성하고 AppLocationService.kt에 다음 코드를 추가합니다. 이 클래스는 GPS 프로바이더를 통해 위치 정보를 가져오는 역할을 합니다.

예제

import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import android.os.IBinder
open class AppLocationService(context: Context) : Service(),
LocationListener {
   private var locationManager: LocationManager? =
   context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
   private lateinit var location: Location
   @SuppressLint("MissingPermission")
   fun getLocation(provider: String?): Location? {
      if (locationManager!!.isProviderEnabled(provider)) {
         locationManager!!.requestLocationUpdates(
         provider,
         MIN_TIME_FOR_UPDATE,
         MIN_DISTANCE_FOR_UPDATE.toFloat(), this
         )
         if (locationManager != null) {
            location = locationManager!!.getLastKnownLocation(provider)
            return location
         }
      }
      return null
   }
   override fun onLocationChanged(location: Location) {}
   override fun onProviderDisabled(provider: String) {}
   override fun onProviderEnabled(provider: String) {}
   override fun onStatusChanged(
   provider: String,
   status: Int,
   extras: Bundle
   ) {
   }
   override fun onBind(arg0: Intent): IBinder? {
      return null
   }
   companion object {
      private const val MIN_DISTANCE_FOR_UPDATE: Long = 10
      private const val MIN_TIME_FOR_UPDATE = 1000 * 60 * 2.toLong()
   }
}

5단계: LocationAddress 클래스 생성

새로운 코틀린 클래스를 생성하고 LocationAddress.kt에 다음 코드를 추가합니다. 이 클래스는 Geocoder를 사용해 위도·경도 좌표를 실제 주소로 변환하며, 네트워크 작업이므로 별도의 스레드에서 실행됩니다.

예제

import android.content.Context
import android.location.Geocoder
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.util.Log
import java.io.IOException
import java.util.*
class LocationAddress {
   private val tag = "LocationAddress"
   fun getAddressFromLocation(
   latitude: Double,
   longitude: Double, context: Context, handler: Handler
   ) {
      val thread = object : Thread() {
         override fun run() {
            val geoCoder = Geocoder(
            context,
            Locale.getDefault()
            )
            var result: String = null.toString()
            try {
               val addressList = geoCoder.getFromLocation(
               latitude, longitude, 1
               )
               if ((addressList != null && addressList.size > 0)) {
                  val address = addressList.get(0)
                  val sb = StringBuilder()
                  for (i in 0 until address.maxAddressLineIndex) {
                     sb.append(address.getAddressLine(i)).append("\n")
                  }
                  sb.append(address.locality).append("\n")
                  sb.append(address.postalCode).append("\n")
                  sb.append(address.countryName)
                  result = sb.toString()
               }
            } catch (e: IOException) {
               Log.e(tag, "Unable connect to GeoCoder", e)
            } finally {
               val message = Message.obtain()
               message.target = handler
               message.what = 1
               val bundle = Bundle()
               result = ("Latitude: " + latitude + " Longitude: " + longitude +
               "\n\nAddress:\n" + result)
               bundle.putString("address", result)
               message.data = bundle
               message.sendToTarget()
            }
         }
      }
      thread.start()
   }
}

6단계: 매니페스트에 권한 추가

androidManifest.xml에 다음 코드를 추가하여 위치 권한을 선언합니다. 이 권한이 없으면 Geocoder와 위치 서비스를 사용할 수 없습니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android" package="app.com.q11">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
   <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">
      <activity android:name=".MainActivity">
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
      </activity>
   </application>
</manifest>

앱 실행 및 결과 확인

이제 애플리케이션을 실행해 보겠습니다. 실제 안드로이드 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 앱을 실행하려면 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바에서 실행(Run) 아이콘을 클릭합니다. 안드로이드 코틀린(Kotlin)에서 위도·경도 좌표로 전체 주소 가져오는 방법 실행 옵션에서 본인의 모바일 기기를 선택하면, 기기 화면에 아래와 같은 기본 화면이 표시됩니다.

안드로이드 코틀린(Kotlin)에서 위도·경도 좌표로 전체 주소 가져오는 방법

버튼을 누르면 지정한 위도·경도 좌표에 해당하는 전체 주소(도시, 우편번호, 국가 정보 포함)가 화면에 표시됩니다. 참고로 Geocoder는 구글 Play 서비스를 기반으로 동작하므로, 기기에 구글 Play 서비스가 설치되어 있고 네트워크에 연결되어 있어야 정상적으로 주소를 가져올 수 있습니다.