1

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 ""
}
Dan Bray
  • 7,242
  • 3
  • 52
  • 70
  • **val locality = addresses[0].locality** is your cityName in Address – X-Byte Technolabs pvt. ltd. Apr 10 '19 at 10:27
  • https://stackoverflow.com/questions/22323974/how-to-get-city-name-by-latitude-longitude-in-android check it out once – Sandeep Insan Apr 10 '19 at 10:29
  • @X-ByteTechnolabspvt.ltd. Maybe for some addresses it is. In Leeds and Wakefield, `locality` returns a small suburb or null. – Dan Bray Apr 10 '19 at 10:29
  • @SandeepInsan I already checked that out before posting. I even mentioned it in my question. All the answers to that question do not work for me. The problem is there are too many variations to how the addresses are stored and too many edge cases to code for and I cannot test for all possible edge cases because there are too many cities and possible locations. – Dan Bray Apr 10 '19 at 10:31

2 Answers2

0
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List addresses = geocoder.getFromLocation(MyLat, MyLong, 1); 
String cityName = addresses.get(0).getAddressLine(0); 
String stateName = addresses.get(0).getAddressLine(1); 
String countryName = addresses.get(0).getAddressLine(2);
mooga
  • 3,136
  • 4
  • 23
  • 38
navya sree
  • 73
  • 7
  • addresses.get(0).getAddressLine(0) contains a lot more than just the city name. With `53.801f` and `-1.549f` it returns `Portland Place, 5 Calverley St, Leeds LS1 3DA, UK`, and sometimes the street name is abbreviated but not in `thoroughfare` so I can't simply remove all the parts of the address that aren't the city to be left with the city. – Dan Bray Apr 10 '19 at 10:40
0
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List addresses = geocoder.getFromLocation(MyLat, MyLong, 1); 
String cityName = addresses.get(0).getLocality();