Get Full Address From Location Coordinates in Android

Today in this tutorial we are going to learn how we can get full address from location coordinates in our Android application. If you are searching about how to get location in Android. Please read this first: How to get current GPS location in Android. And then again come back here.

Here we will only be focusing on the coordinates which we already have. Eg: 41.40338, 2.17403. Let us see how we can accomplish this task without using any Google location APIs.

What is Geocode ?

Geocode is the non human readable piece of information such as a place name or address on the surface of the earth. Or simply we can understand that Geocode is the latitude and longitude. It represents a specific point on the surface of the earth.

Unlike us humans, who can make sense of address. It is hard for computers to understand human readable form. So these points are used as the index to retrieve more information about that place.

And, Geocoding is the process of converting any input such as address or human readable location to latitude and longitude.

In this post we will be looking at how to convert coordinates into human readable form. The process is known as reverse Geocoding. But before diving in I had to provide you some context about Geocoding.

Also Read : Learn how to use fileprovider in Android with example

TECHENUM

What is Reverse Geocode ?

In the section above we have seen that how the process of converting readable information to coordinates is Geocoding.

Reverse Geocoding is just the opposite of that. Reverse Geocode is the human readable information for a certain point. Or in regular terms, address.

We have multiple ways on how to do this. We can use the API provided by Google or any other map provider. Here we will learn how to do this without using any other online services.

Using the Geocode class in Android

To do what I have described, we must make use of Geocode class in Android SDK.

This will not cost us anything whatsoever. But sometimes the rate limiting might not provide information about the coordinates. But this has never happened with me.

Let us see how we can do just that. We are going to use this address here : 37.474976, -122.171610

Want to get your device’s current location instead ? Read this: How to get current GPS location in Android

Also Read : 3 Essential Datastructures in Object Oriented Programming

TECHENUM

Preparing UI for showing address

Let us first prepare a UI for showing the address.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/result"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:text="Please enter latitude and longitude below"
        android:textAlignment="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@+id/input"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="@+id/input"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.24000001" />

    <EditText
        android:id="@+id/input"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:ems="10"
        android:hint="latitude, longitude"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/result" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textAlignment="center"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toTopOf="@+id/result"
        app:layout_constraintEnd_toEndOf="@+id/result"
        app:layout_constraintStart_toStartOf="@+id/result"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>Code language: HTML, XML (xml)

Now mapping our views to activity class member instances as under. Notice we have created extra methods which are not required. This is just a scaffold for what we are doing up next.

class MainActivity : AppCompatActivity() {

    private lateinit var mInput: EditText
    private lateinit var mResult: TextView
    private lateinit var mDone: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mInput = findViewById(R.id.input)
        mResult = findViewById(R.id.result)
        mDone = findViewById(R.id.done)
        mDone.setOnClickListener {
            val latLon: Pair<Double, Double> = parseInput()
            doReverseGeoCode(latLon)
        }

    }

    private fun doReverseGeoCode(latLon: Pair<Double, Double>) {

    }

    private fun parseInput(): Pair<Double, Double> {

    }

}Code language: Kotlin (kotlin)

Performing a Reverse Geocode

Now that we have our scaffold ready from previous section. Let us actually do some reverse Geocoding. But first let us parse the user input into Pair<*> of Double.

Also Read : Async Task in Android is Deprecated: There are Better Ways

TECHENUM

Parsing the input

This is optional because it is related to this example project only. Just prepare a model or another pair for your data.

I have created a method to parse the user input and convert it into Pair<> of latitude and longitude.

private fun parseInput(): Pair<Double, Double> {
    var lat = 0.0
    var lon = 0.0

    val input = mInput.text.toString()
    val arrInput = input.split(",")

    // invalid input
    if (arrInput.size != 2) return Pair(lat, lon)

    try {
        lat = arrInput[0].toDouble()
        lon = arrInput[1].toDouble()
    } catch (ex: NumberFormatException) {
        // no a double value return the pointer
        return Pair(lat, lon)
    }

    return Pair(lat, lon)
}Code language: Kotlin (kotlin)

All the code above does is parses the input and returns a Pair<>.

Doing the reverse Geocoding

Now after we have successfully parsed the input. The next step is actually performing reverse Geocoding as follows.

private fun doReverseGeoCode(latLon: Pair<Double, Double>) {
    mExecutorService.submit {

        val geocoder = Geocoder(this, Locale.ENGLISH)
        val addresses = geocoder.getFromLocation(latLon.first, latLon.second, 1)

        if (addresses.isEmpty()) {
            updateUi("address not found for: ${latLon.first}, ${latLon.second}")
            return@submit
        }

        val address = addresses.first()

        val premises = address.premises
        val featureName = address.featureName

        val countryName = address.countryName

        val adminArea = address.adminArea
        val subAdminArea = address.subAdminArea

        val locality = address.locality
        val subLocality = address.subLocality

        val thoroughfare = address.thoroughfare
        val subThoroughfare = address.subThoroughfare

        val result =
            "premise: $premises\nfeature: $featureName\ncountry: $countryName\nadmin area: $adminArea\nsub admin area: $subAdminArea\nlocality: $locality\nsub locality: $subLocality\nthoroughfare: $thoroughfare\nsub thoroughfare: $subThoroughfare"
        updateUi(result)
    }
}Code language: Kotlin (kotlin)

Finally create the missing method named updateUi() { } like below. All is does is runs the UI update code in the UiThread.

private fun updateUi(result: String) {
    runOnUiThread {
        mResult.text = result
    }
}Code language: Kotlin (kotlin)

And now invoke these methods in the click listener that we have set in onCreate() { }.

val latLon: Pair<Double, Double> = parseInput()
doReverseGeoCode(latLon)Code language: Kotlin (kotlin)

The full code for MainActivity looks like this :

class MainActivity : AppCompatActivity() {

    private val mExecutorService = Executors.newSingleThreadExecutor()

    private lateinit var mInput: EditText
    private lateinit var mResult: TextView
    private lateinit var mDone: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mInput = findViewById(R.id.input)
        mResult = findViewById(R.id.result)
        mDone = findViewById(R.id.done)
        mDone.setOnClickListener {
            val latLon: Pair<Double, Double> = parseInput()
            doReverseGeoCode(latLon)
        }

    }

    private fun updateUi(result: String) {
        runOnUiThread {
            mResult.text = result
        }
    }

    private fun doReverseGeoCode(latLon: Pair<Double, Double>) {
        mExecutorService.submit {

            val geocoder = Geocoder(this, Locale.ENGLISH)
            val addresses = geocoder.getFromLocation(latLon.first, latLon.second, 1)

            if (addresses.isEmpty()) {
                updateUi("address not found for: ${latLon.first}, ${latLon.second}")
                return@submit
            }

            val address = addresses.first()

            val premises = address.premises
            val featureName = address.featureName

            val countryName = address.countryName

            val adminArea = address.adminArea
            val subAdminArea = address.subAdminArea

            val locality = address.locality
            val subLocality = address.subLocality

            val thoroughfare = address.thoroughfare
            val subThoroughfare = address.subThoroughfare

            val result =
                "premise: $premises\nfeature: $featureName\ncountry: $countryName\nadmin area: $adminArea\nsub admin area: $subAdminArea\nlocality: $locality\nsub locality: $subLocality\nthoroughfare: $thoroughfare\nsub thoroughfare: $subThoroughfare"
            updateUi(result)
        }
    }

    private fun parseInput(): Pair<Double, Double> {
        var lat = 0.0
        var lon = 0.0

        val input = mInput.text.toString()
        val arrInput = input.split(",")

        // invalid input
        if (arrInput.size != 2) return Pair(lat, lon)

        try {
            lat = arrInput[0].toDouble()
            lon = arrInput[1].toDouble()
        } catch (ex: NumberFormatException) {
            // no a double value return the pointer
            return Pair(lat, lon)
        }

        return Pair(lat, lon)
    }

}Code language: Kotlin (kotlin)

That is all there is to reverse Geocoding. And in this article we have seen how to get address from location coordinates in Android.

Leave a comment if you think I made any mistakes. Keep learning.

For more on this you can see Official Documentation.

Related Posts