Reverse Geocoding in Android
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 & 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?
Project Structure
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.
What we are going to build in this article?
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?.
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 android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context = ".MainActivity" > <!--Map Fragment--> 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 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.ApplicationInfo import android.content.pm.PackageManager import android.location.Address import android.location.Geocoder import android.os.Bundle import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap.OnCameraIdleListener import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.SupportMapFragment import com.google.android.gms.maps.model.LatLng import com.google.android.libraries.places.api.Places import java.io.IOException import 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.
Please Login to comment...