Reverse Geocoding in Android

15 Feb, 2022
Reverse-Geocoding is a process used to convert coordinates (latitude and longitude) to human-readable addresses. This is not exactly the opposite of Geocoding. In Geocoding, the Place is associated with a name and fixed coordinates. These coordinates are Double in nature. Negligible change in these coordinates may still refer to the same place, but we shall never get the place name as it is associated with only those fixed coordinates. Therefore, we shall definitely get the complete address in reverse geocoding, but the place name is not guaranteed. Through this article, we will show you an example of how to perform reverse-geocoding in Android. But before moving ahead, please refer to the below articles:
Google Cloud Platform – Creating Google Cloud Console Account & ProjectsGenerating API Keys For Using Any Google APIsHow to Hide API and Secret Keys in Android Studio?How to Implement Google’s Places AutocompleteBar in Android?How to Implement Current Location Button Feature in Google Maps in Android?
Google Cloud Platform – Creating Google Cloud Console Account & Projects
Generating API Keys For Using Any Google APIs
How to Hide API and Secret Keys in Android Studio?
How to Implement Google’s Places AutocompleteBar in Android?
How to Implement Current Location Button Feature in Google Maps in Android?
For reverse-geocoding, we will need latitude and longitude in Double data type. So we will implement a Google Map and consider its center as our primary latitude and longitude. We can easily get the center coordinates using the camera position (refer to main code). Whenever the Map is dragged, the center will change and cause a change in latitude and longitude. Once the Map is idle, i.e. it stops being dragged or moving, the reverse geocoding algorithm will consider the center coordinates and process them to get a complete address. This will then be instantly posted to a textView. This will confirm that reverse-geocoding works fine in the code. Follow the below steps to create this project.
Step 1: Create a New Project in Android Studio
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. We demonstrated the application in Kotlin, so make sure you select Kotlin as the primary language while creating a New Project.
Step 2: Get and hide API Key
Our application utilizes Google’s Places API, so we need to get the Places API key from Google. To get an API key, please refer to Generating API Keys For Using Any Google APIs.Hiding an API key is essential and to do so, please refer to How to Hide API and Secret Keys in Android Studio?.
Our application utilizes Google’s Places API, so we need to get the Places API key from Google. To get an API key, please refer to Generating API Keys For Using Any Google APIs.
Hiding an API key is essential and to do so, please refer to How to Hide API and Secret Keys in Android Studio?.
Step 3: Add these dependencies
This dependency will be required for reverse geocoding.
Kotlin
dependencies {    implementation 'com.google.android.libraries.places:places:2.4.0'}
Step 4: Adding a Map fragment, a custom location marker, and a text view in the layout (activity_main.xml) file
XML
<?xml version="1.0" encoding="utf-8"?><RelativeLayout    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">      <!--Map Fragment-->    <fragment xmlns:android="http://schemas.android.com/apk/res/android"        xmlns:tools="http://schemas.android.com/tools"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:id="@+id/map"        tools:context=".MapsActivity"        android:name="com.google.android.gms.maps.SupportMapFragment" />      <!--This layout overlays the Map Fragment         which matches parent width and height-->    <!--We want to display our TextView over         the Map with good aesthetics-->    <LinearLayout        android:layout_margin="20sp"        android:id="@+id/ll1"        android:layout_width="match_parent"        android:layout_height="100sp"        android:background="@drawable/shape"        android:layout_alignBottom="@id/map"        android:orientation="horizontal">            <!--TextView for displaying Lat and             Lng along with Address-->        <TextView            android:id="@+id/tv"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_margin="10sp"            />      </LinearLayout>        <!--This is only for reference to the center         of the screen, can be any element-->      <!--We have set fixed this element at the parent         center, which is the actual centre of the screen-->    <Button        android:id="@+id/centerReferencePoint"        android:layout_width="0sp"        android:layout_height="0sp"        android:layout_centerInParent="true"/>        <!--This image is the Marker-->    <ImageView        android:id="@+id/marker"        android:layout_width="30sp"        android:layout_height="40sp"        android:src="@drawable/marker"        android:layout_centerInParent="true"        android:layout_above="@id/centerReferencePoint"        />  </RelativeLayout>
Marker:
We downloaded this image in PNG format from the internet. It has no background color and can be referred to as a transparent image. Once downloaded, you can directly copy it from wherever it is stored, open Android Studio, and paste it into the drawable folder present in the res folder. While doing this, we renamed it as “marker” which you may find in the ImageView attributes in the activity_main.xml.
Shape.xml file (Background of the Linear Layout in activity_main.xml)
We have set a white background and corner radius with some value. This is to make the layout look better.
XML
<shape    xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle"   >      <solid        android:color="#ffffff" >    </solid>      <corners        android:radius="11dp"   >    </corners>  </shape>
Preview of Shape.xml
Preview of activity_main.xml:
activity_main.xml preview
Step 5: Working on the backend (MainActivity.kt)
We take the coordinates of the place present at the center of the screen and convert them into text addresses. Once the screen is dragged, the center coordinates change and the address change respectively. Changes take place once the screen is idle and not in motion and that’s why we implemented our reverse-geocoding algorithm in the setOnCameraIdleListener. The below code is quite easy to understand. We have provided some comments to help you understand better.
Kotlin
package org.geeksforgeeks.reversegeocoding  import android.content.pm.ApplicationInfoimport android.content.pm.PackageManagerimport android.location.Addressimport android.location.Geocoderimport android.os.Bundleimport android.widget.TextViewimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport com.google.android.gms.maps.CameraUpdateFactoryimport com.google.android.gms.maps.GoogleMapimport com.google.android.gms.maps.GoogleMap.OnCameraIdleListenerimport com.google.android.gms.maps.OnMapReadyCallbackimport com.google.android.gms.maps.SupportMapFragmentimport com.google.android.gms.maps.model.LatLngimport com.google.android.libraries.places.api.Placesimport java.io.IOExceptionimport java.util.*    class MainActivity : AppCompatActivity(), OnMapReadyCallback {      private lateinit var mMap: GoogleMap      override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)          // Fetching API_KEY which we wrapped        val ai: ApplicationInfo = applicationContext.packageManager.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)        val value = ai.metaData["com.google.android.geo.API_KEY"]        val apiKey = value.toString()          // Initializing the Places API          // with the help of our API_KEY        if (!Places.isInitialized()) {            Places.initialize(applicationContext, apiKey)        }          // Initializing map        val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment        mapFragment.getMapAsync(this)      }      override fun onMapReady(p0: GoogleMap) {                mMap = p0                  // These are GeeksforGeeks Noida Office Coordinates.        val india = LatLng(28.5021359, 77.4054901)        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(india,17F))          mMap.setOnCameraIdleListener {            val lat = mMap.cameraPosition.target.latitude            val lng = mMap.cameraPosition.target.longitude            val addressTV = findViewById<TextView>(R.id.tv)              // Initializing Geocoder            val mGeocoder = Geocoder(applicationContext, Locale.getDefault())            var addressString= ""                // Reverse-Geocoding starts            try {                val addressList: List<Address> = mGeocoder.getFromLocation(lat, lng, 1)                  // use your lat, long value here                if (addressList != null && addressList.isNotEmpty()) {                    val address = addressList[0]                    val sb = StringBuilder()                    for (i in 0 until address.maxAddressLineIndex) {                        sb.append(address.getAddressLine(i)).append("\n")                    }                      // Various Parameters of an Address are appended                      // to generate a complete Address                    if (address.premises != null)                        sb.append(address.premises).append(", ")                                              sb.append(address.subAdminArea).append("\n")                    sb.append(address.locality).append(", ")                    sb.append(address.adminArea).append(", ")                    sb.append(address.countryName).append(", ")                    sb.append(address.postalCode)                                          // StringBuilder sb is converted into a string                     // and this value is assigned to the                     // initially declared addressString string.                    addressString = sb.toString()                }            } catch (e: IOException) {                Toast.makeText(applicationContext,"Unable connect to Geocoder",Toast.LENGTH_LONG).show()            }                          // Finally, the address string is posted in the textView with LatLng.            addressTV.text = "Lat: $lat \nLng: $lng \nAddress: $addressString"        }    }}
Output:
Observe, the address changes with a change in lat-long values. Lat-long values change when the user drags the screen, as the center keeps changing.
clintra
Android
Google Cloud Platform
Kotlin
Android
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Difference Between Implicit Intent and Explicit Intent in Android
Retrofit with Kotlin Coroutine in Android
Flutter - BoxShadow Widget
Bundle in Android with Example
Animation in Android with Example
Kubernetes vs Docker
Difference Between Google Cloud Compute Engine and App Engine
Google Cloud Platform - Introduction to PhoneInfoga an OSINT Reconnaissance Tool
Google Cloud Platform - Managing Access using IAM in BigQuery
How to Build G Suite Add-ons with Google Apps script?