Use an online service to find the address for a tapped point.

Use case
You might use a geocoder to find a customer’s delivery address based on the location returned by their device’s GPS.
How to use the sample
Tap the map to see the nearest address displayed as a text view.
How it works
- Create a
LocatorTaskobject using a URL to a geocoder service. - Get the matching results from the
GeocodeResultusingLocatorTask.reverseGeocode. - Show the results using a
PictureMarkerSymboland add the symbol to aGraphicin theGraphicsOverlay.
Relevant API
- GeocodeParameters
- GeocodeResult
- LocatorTask
- ReverseGeocodeParameters
Additional information
This sample uses the World Geocoding Service. For more information, see the Geocoding service help topic on the ArcGIS Developer website.
Tags
address, geocode, locate, reverse geocode, search
Sample Code
MainActivity.kt
/* Copyright 2022 Esri * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */
package com.esri.arcgismaps.sample.findaddresswithreversegeocode
import android.graphics.drawable.BitmapDrawableimport android.os.Bundleimport android.util.Logimport com.esri.arcgismaps.sample.sampleslib.EdgeToEdgeCompatActivityimport androidx.core.content.ContextCompatimport androidx.databinding.DataBindingUtilimport androidx.lifecycle.lifecycleScopeimport com.arcgismaps.ApiKeyimport com.arcgismaps.ArcGISEnvironmentimport com.arcgismaps.geometry.GeometryEngineimport com.arcgismaps.geometry.Pointimport com.arcgismaps.mapping.ArcGISMapimport com.arcgismaps.mapping.BasemapStyleimport com.arcgismaps.mapping.Viewpointimport com.arcgismaps.mapping.symbology.PictureMarkerSymbolimport com.arcgismaps.mapping.view.Graphicimport com.arcgismaps.mapping.view.GraphicsOverlayimport com.arcgismaps.tasks.geocode.LocatorTaskimport com.esri.arcgismaps.sample.findaddresswithreversegeocode.databinding.FindAddressWithReverseGeocodeActivityMainBindingimport com.google.android.material.snackbar.Snackbarimport kotlinx.coroutines.launch
class MainActivity : EdgeToEdgeCompatActivity() {
// service url to be provided to the LocatorTask (geocoder) private val geocodeServer = "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer"
// set up data binding for the activity private val activityMainBinding: FindAddressWithReverseGeocodeActivityMainBinding by lazy { DataBindingUtil.setContentView(this, R.layout.find_address_with_reverse_geocode_activity_main) }
// create a MapView using binding private val mapView by lazy { activityMainBinding.mapView }
// display the street of the tapped location private val titleTV by lazy { activityMainBinding.titleTV }
// display the metro area of the tapped location private val descriptionTV by lazy { activityMainBinding.descriptionTV }
// set the pin graphic for tapped location private val pinSymbol by lazy { createPinSymbol() }
// create a graphics overlay private val graphicsOverlay = GraphicsOverlay()
// locator task to provide geocoding services private val locatorTask = LocatorTask(geocodeServer)
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
// authentication with an API key or named user is // required to access basemaps and other location services ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.ACCESS_TOKEN) lifecycle.addObserver(mapView)
mapView.apply { // add a map with a imagery basemap style map = ArcGISMap(BasemapStyle.ArcGISImagery) // add a graphics overlay to the map for showing where the user tapped graphicsOverlays.add(graphicsOverlay) // set initial viewpoint setViewpoint(Viewpoint(34.058, -117.195, 5e4)) }
lifecycleScope.launch { // load geocode locator task locatorTask.load().onSuccess { // locator task loaded, look for geo view tapped mapView.onSingleTapConfirmed.collect { event -> event.mapPoint?.let { mapPoint -> geoViewTapped(mapPoint) } } }.onFailure { showError(it.message.toString()) } } }
/** * Displays a pin of the tapped location using [mapPoint] * and finds address with reverse geocode */ private suspend fun geoViewTapped(mapPoint: Point) { // create graphic for tapped point val pinGraphic = Graphic(mapPoint, pinSymbol) graphicsOverlay.graphics.apply { // clear existing graphics clear() // add the pin graphic add(pinGraphic) } // normalize the geometry - needed if the user crosses the international date line. val normalizedPoint = GeometryEngine.normalizeCentralMeridian(mapPoint) as Point // reverse geocode to get address locatorTask.reverseGeocode(normalizedPoint).onSuccess { addresses -> // get the first result val address = addresses.firstOrNull() if (address == null) { showError("Could not find address at tapped point") return@onSuccess } // use the street and region for the title val title = address.attributes["Address"].toString() // use the metro area for the description details val description = "${address.attributes["City"]} " + "${address.attributes["Region"]} " + "${address.attributes["CountryCode"]}" // set the strings to the text views titleTV.text = title descriptionTV.text = description }.onFailure { showError(it.message.toString()) } }
/** * Create a picture marker symbol to represent a pin at the tapped location */ private fun createPinSymbol(): PictureMarkerSymbol { // get pin drawable val pinDrawable = ContextCompat.getDrawable( this, R.drawable.baseline_location_pin_red_48 ) //add a graphic for the tapped point val pinSymbol = PictureMarkerSymbol.createWithImage( pinDrawable as BitmapDrawable ) pinSymbol.apply { // resize the dimensions of the symbol width = 50f height = 50f // the image is a pin so offset the image so that the pinpoint // is on the point rather than the image's true center leaderOffsetX = 30f offsetY = 25f } return pinSymbol }
private fun showError(errorMessage: String) { Log.e(localClassName, errorMessage) Snackbar.make(mapView, errorMessage, Snackbar.LENGTH_SHORT).show() }}