In Android (either Java or Kotlin is fine) how can I get the city name from the longitude and latitude?
Below I've written a function to display address data. I would like to modify it so that it returns the city name:
private fun getCity(context: Context, latitude: Float, longitude: Float) {
val gcd = Geocoder(context, Locale.getDefault())
val addresses = gcd.getFromLocation(latitude.toDouble(), longitude.toDouble(), 1)
Log.d("-----", "-----")
Log.d("latitude", latitude.toString())
Log.d("longitude", longitude.toString())
if (addresses.size > 0) {
val locality = addresses[0].locality
if (locality != null) {
Log.d("locality", locality.toString())
}
val adminArea = addresses[0].adminArea
if (adminArea != null) {
Log.d("adminArea", adminArea.toString())
}
val subAdminArea = addresses[0].subAdminArea
if (subAdminArea != null) {
Log.d("subAdminArea", subAdminArea.toString())
}
val subLocality = addresses[0].subLocality
if (subLocality != null) {
Log.d("subLocality", subLocality.toString())
}
val thoroughfare = addresses[0].thoroughfare
if (thoroughfare != null) {
Log.d("thoroughfare", thoroughfare.toString())
}
val subThoroughfare = addresses[0].subThoroughfare
if (subThoroughfare != null) {
Log.d("subThoroughfare", subThoroughfare.toString())
}
val extras = addresses[0].extras
if (extras != null) {
Log.d("extras", extras.toString())
}
val premises = addresses[0].premises
if (premises != null) {
Log.d("premises", premises.toString())
}
val postalCode = addresses[0].postalCode
if (postalCode != null) {
Log.d("postalCode", postalCode.toString())
}
val featureName = addresses[0].featureName
if (featureName != null) {
Log.d("featureName", featureName.toString())
}
val getAddressLine0 = addresses[0].getAddressLine(0)
if (getAddressLine0 != null)
Log.d("getAddressLine0", getAddressLine0.toString())
for (i in 0 until addresses[0].maxAddressLineIndex) {
Log.d("getAddressLine($i)", addresses[0].getAddressLine(i).toString())
}
}
}
If I run getCity(context, 53.7f, -1.506f)
, featureName
contains the correct city name, Wakefield.
If I run getCity(context, 53.801f, -1.549f)
, featureName
now contains the street name, Portland Place. getAddressLine(0)
return Portland Place, 5 Calverley St, Leeds LS1 3DA, UK, which contains the correct city, Leeds. I could remove the street name, post code, and house number from getAddressLine(0) to be left with the city. Unfortunately, there are edge cases where that won't work because sometimes the street name contains abbreviations in getAddressLine(0)
but not in thoroughfare
.
This question How to Get City Name by Latitude &Longitude in android? has answers that are completely different because the addresses in different countries are stored in a different way.
There seem to be quite a few variations and edge cases I need to code for just to get the city name for 2 neighbouring cities in the UK. How can I get the correct city name from any latitude or longitude world wide? There are way too many cities in the world to test my code against and code for, and there may be many edge cases and variations that I am unaware even exist.
Edit
The function below correctly gets the city in the UK. Unfortunately, it fails in the USA and India and probably any country that has states.
private fun getCity(context: Context, latitude: Float, longitude: Float): String {
val gcd = Geocoder(context, Locale.getDefault())
val addresses = gcd.getFromLocation(latitude.toDouble(), longitude.toDouble(), 1)
if (addresses.size > 0) {
val locality = addresses[0].locality
val getAddressLine0 = addresses[0].getAddressLine(0)
if (getAddressLine0 != null) {
val strs = getAddressLine0.split(",").toTypedArray()
if (strs.count() == 1) {
if (locality != null && locality != "") {
return "$locality, ${strs[0]}"
}
return strs[0]
}
for (str in strs) {
var tempStr = str.replace(postalCode, "")
if (tempStr != str) {
tempStr = tempStr.trim()
if (locality != null && locality != "" && locality != tempStr) {
return "$locality, $tempStr"
}
return tempStr
}
}
}
if (locality != null) {
return locality
}
}
return ""
}