Learn how to find an address or place with a search bar and the Geocoding service.
Geocoding is the process of converting address or place text into a location. The geocoding service can search for an address or a place and perform reverse geocoding.
In this tutorial, you use a search bar in the user interface to access the geocoding service and search for addresses and places.
To learn how to use the geocoding service to reverse geocode, visit the Reverse geocode tutorial.
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Confirm that your system meets the system requirements.
-
An IDE for Android development in Kotlin.
Steps
Get an access token
You need an access token to use the location services used in this tutorial.
-
Go to the Create an API key tutorial to obtain an access token.
-
Ensure that the following privileges are enabled: Location services > Basemaps > Basemap styles service and Location services > Geocoding.
-
Copy the access token as it will be used in the next step.
To learn more about other ways to get an access token, go to Types of authentication.
Open an Android Studio project
-
To start this tutorial, complete the Display a map tutorial. Or download and unzip the Display a map solution in a new folder.
-
Modify the old project for use in this new tutorial. Expand More info for instructions.
-
On your file system, delete the .idea folder, if present, at the top level of your project.
-
In the Android tool window, open app > res > values > strings.xml.
In the
<string name="app
element, change the text content to Search for an address._name" > strings.xmlUse dark colors for code blocks 1 2 4 5Change line <resources> <string name="app_name">Search for an address</string> </resources>
-
In the Android tool window, open Gradle Scripts > settings.gradle.
Change the value of
root
to "Search for an address".Project.name settings.gradleUse dark colors for code blocks 23 24Change line rootProject.name = "Search for an address" include ':app'
-
Click File > Sync Project with Gradle files. Android Studio will recognize your changes and create a new .idea folder.
-
-
Set the API key using the copied access token.
-
In Android Studio: in the Android tool window, open app > java > com.example.app > MainActivity.
-
In the
set
method, find theApi Key For App() ArcGIS
call and paste your access token inside the double quotes, replacing YOUR_ACCESS_TOKEN.Runtime Environment.set Api Key(" YOUR _ACCESS _TOKE N") MainActivity.ktUse dark colors for code blocks private fun setApiKeyForApp(){ ArcGISRuntimeEnvironment.setApiKey("YOUR_ACCESS_TOKEN") }
-
Add import statements
Modify import statements to reference the packages and classes required for this tutorial.
-
In Android Studio, in the Android tool window, open app > java > com.example.app > MainActivity.
-
Replace app-specific import statements with the imports needed for this tutorial.
MainActivity.ktUse dark colors for code blocks 17 18 19 20 21 39 40Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line package com.example.app import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import android.graphics.Color import android.util.Log import android.widget.SearchView import android.widget.Toast import com.esri.arcgisruntime.ArcGISRuntimeEnvironment import com.esri.arcgisruntime.mapping.ArcGISMap import com.esri.arcgisruntime.mapping.BasemapStyle import com.esri.arcgisruntime.mapping.Viewpoint import com.esri.arcgisruntime.mapping.view.Graphic import com.esri.arcgisruntime.mapping.view.GraphicsOverlay import com.esri.arcgisruntime.mapping.view.MapView import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol import com.esri.arcgisruntime.symbology.TextSymbol import com.esri.arcgisruntime.tasks.geocode.GeocodeParameters import com.esri.arcgisruntime.tasks.geocode.GeocodeResult import com.esri.arcgisruntime.tasks.geocode.LocatorTask import com.example.app.databinding.ActivityMainBinding
Declare graphics overlay and locator task and initialize map view
A graphics overlay is a container for graphics. A locator task converts an address to a point. You will create the properties graphics
and locator
for use later in later steps. Next you will initialize the map
.
-
In the
Main
method, create a lazy property namedActivity graphics
that references a newOverlay Graphics
for storing geocode result graphics (address location and label).Overlay Since
graphics
is a lazy property, aOverlay Graphics
will not be created until the property is initialized, which occurs in theOverlay setup
method that you will modify shortly.Map() MainActivity.ktUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 55Add line. Add line. Add line. class MainActivity : AppCompatActivity() { private val activityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) } private val mapView: MapView by lazy { activityMainBinding.mapView } private val graphicsOverlay: GraphicsOverlay by lazy { GraphicsOverlay() }
-
Create a property named
locator
that references a newTask Locator
for geocoding an address.Task MainActivity.ktUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55Add line. class MainActivity : AppCompatActivity() { private val activityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) } private val mapView: MapView by lazy { activityMainBinding.mapView } private val graphicsOverlay: GraphicsOverlay by lazy { GraphicsOverlay() } private val locatorTask = LocatorTask("https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")
-
At the end of the
setup
method, initialize theMap map
by calling the scope functionView apply
and passing a lambda expression that does the following:- assigns the local variable
arc
to theGI Smap map
property - creates a
Viewpoint
and pass it toset
Viewpoint() - adds
graphics
to theOverlay graphics
collection.Overlays
Declared at the start of the
Main
class, the lazy propertyActivity graphics
is initialized at its first access, which is in this lambda expression. The newOverlay Graphics
is not created until now.Overlay MainActivity.ktUse dark colors for code blocks 87 88 89 90 91 101 102Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. // set up your map here. You will call this method from onCreate() private fun setupMap() { // create a map with the BasemapStyle topographic val arcGISmap = ArcGISMap(BasemapStyle.ARCGIS_TOPOGRAPHIC) mapView.apply { // set the map to be displayed in the layout's MapView map = arcGISmap // set the viewpoint, Viewpoint(latitude, longitude, scale) setViewpoint(Viewpoint(34.0270, -118.8050, 72000.0)) graphicsOverlays.add(graphicsOverlay) } }
- assigns the local variable
Add a UI for user input
To search an address using the application, add a UI element to prompt the user for text input. The text input will be used as the geocode search text in a later step.
-
In activity_main.xml, add a
Search
element. This widget will display a search text field at the top of the app window.View activity_main.xmlUse dark colors for code blocks 3 4 5 6 7 8 9 19Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. <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"> <SearchView android:id="@+id/searchView" android:layout_width="0dp" android:layout_height="0dp" android:queryHint="@string/search_hint" app:layout_constraintBottom_toTopOf="@+id/guideline" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
-
In MainActivity.kt, create a
setup
method to handle user activity by changing the current address in the search field and submitting the search. In the first line, get the boundSearch View Listener() search
by callingView activity
. Then callMain Binding.search View set
and pass an anonymous class that implements theOn Query Text Listener() Search
interface.View. On Query Text Listener MainActivity.ktUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. private fun setupSearchViewListener() { activityMainBinding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { }) }
-
Implement the two methods of the
Search
interface:View. On Query Text Listener on
andQuery Text Change() on
.Query Text Submit() - Returning
false
specifies the standard Android behavior.
MainActivity.ktUse dark colors for code blocks 106 107 108 109 118 119 120Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private fun setupSearchViewListener() { activityMainBinding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextChange(newText: String): Boolean { return false } override fun onQueryTextSubmit(query: String): Boolean { return false } }) }
- Returning
-
In the
on
lifecycle method, add aCreate() setup
call.Search View Listener() MainActivity.ktUse dark colors for code blocks 58 59 60 61 62 63 64 65 67 68Add line. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(activityMainBinding.root) setApiKeyForApp() setupMap() setupSearchViewListener() }
Create a function to geocode an address
Geocoding is implemented with a locator, typically created by referencing a service such as the Geocoding service or, for offline geocoding, by referencing locator data contained in a mobile package. Geocoding parameters can be used to refine the results, such as setting a maximum number of results or requesting additional attributes in the results.
-
Create a method named
perform
.Geocode() -
Create a new
Geocode
and initialize it by calling the scope functionParameters apply
and passing a lambda expression that does the following:- Adds the names of result attributes to the
result
collection. These are the names of attributes to be returned. An asterisk (Attribute Names *
) indicates all attributes. - Sets
max
to the maximum number of results to be returned. Results are ordered byResults score
, so that the first result has the best match score (ranging from 0 for no match to 100 for the best match). - Sets
output
to the spatial reference for result locations. By default, the output spatial reference is defined by the geocode service. For optimal performance when displaying the geocode result, you can ensure that returned coordinates match those of the map view by providing the map view's spatial reference.Spatial Reference
When geocoding an address, you can optionally provide
Geocode
to control certain aspects of the geocoding operation and specify the kinds of results to return from the locator task. Learn more about these parameters in the API documentation. For a list of attributes returned with geocode results, see Geocoding service output in the ArcGIS services reference.Parameters MainActivity.ktUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private fun performGeocode(query: String) { val geocodeParameters = GeocodeParameters().apply { resultAttributeNames.add("*") maxResults = 1 outputSpatialReference = mapView.spatialReference } }
- Adds the names of result attributes to the
-
To find the location for the provided address, call
geocode
on theAsync() locator
, passing theTask query
(the address to find) and thegeocode
. The call returns aParameters Listenable
, which you should store in the read-only variableFuture geocode
.Result Future MainActivity.ktUse dark colors for code blocks 124 125 126 127 128 129 130 131 133 134Add line. private fun performGeocode(query: String) { val geocodeParameters = GeocodeParameters().apply { resultAttributeNames.add("*") maxResults = 1 outputSpatialReference = mapView.spatialReference } val geocodeResultFuture = locatorTask.geocodeAsync(query, geocodeParameters) }
-
Call
add
onDone Listener geocode
and specify a lambda expression to be executed when geocoding is complete. In the lambda, callResult Future display
to display the first item in theResult(geocode Result[0]) geocode
list. This is the location of the address on the map. In this tutorial, the maximum results parameter was set to 1, so you pass the first and only item in theResult geocode
list.Result MainActivity.ktUse dark colors for code blocks 124 125 126 127 128 129 130 131 132 133 147 148Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private fun performGeocode(query: String) { val geocodeParameters = GeocodeParameters().apply { resultAttributeNames.add("*") maxResults = 1 outputSpatialReference = mapView.spatialReference } val geocodeResultFuture = locatorTask.geocodeAsync(query, geocodeParameters) geocodeResultFuture.addDoneListener { try { val geocodeResult = geocodeResultFuture.get() if (geocodeResult.isNotEmpty()) { displayResult(geocodeResult[0]) } else { Toast.makeText(this, "No results found.", Toast.LENGTH_LONG).show() } } catch (e: Exception) { Log.e(MainActivity::class.simpleName, "Error getting result" + e.message) } } }
-
In the
setup
method, find theSearch View Listener() on
method of theQuery Text Submit() Search
interface implementation, and callView. On Query Text Listener perform
.Code() MainActivity.ktUse dark colors for code blocks 108 109 110 111 112 113 114 115 116 117 119 120 121 122 123 124Add line. private fun setupSearchViewListener() { activityMainBinding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextChange(newText: String): Boolean { return false } override fun onQueryTextSubmit(query: String): Boolean { performGeocode(query) return false } }) }
Display the result
The result obtained from the geocode operation can be displayed by adding two graphics to the map view's graphics overlay: one graphic that shows the address text and the other a red location marker.
-
Create a method named
display
and clear the graphics overlay of any previous result.Result() MainActivity.ktUse dark colors for code blocks 152 153 156 157Add line. Add line. private fun displayResult(geocodeResult: GeocodeResult) { // clear the overlay of any previous result graphicsOverlay.graphics.clear() }
-
Create a
Text
for displaying the address text on the map. Then create aSymbol Graphic
, passing thegeocode
(the location on the map) and theResult.display Location text
. Finally, add the graphic to theSymbol graphics
collection.Overlay MainActivity.ktUse dark colors for code blocks 152 153 154 155 156 165 168 169Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private fun displayResult(geocodeResult: GeocodeResult) { // clear the overlay of any previous result graphicsOverlay.graphics.clear() // create a graphic to display the address text val textSymbol = TextSymbol( 18f, geocodeResult.label, Color.BLACK, TextSymbol.HorizontalAlignment.CENTER, TextSymbol.VerticalAlignment.BOTTOM ) val textGraphic = Graphic(geocodeResult.displayLocation, textSymbol) graphicsOverlay.graphics.add(textGraphic) }
-
Create a graphic to display a red marker symbol indicating the location on the map, and add the graphic to the
graphics
collection.Overlay MainActivity.ktUse dark colors for code blocks 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 172 176 177Add line. Add line. Add line. Add line. Add line. Add line. private fun displayResult(geocodeResult: GeocodeResult) { // clear the overlay of any previous result graphicsOverlay.graphics.clear() // create a graphic to display the address text val textSymbol = TextSymbol( 18f, geocodeResult.label, Color.BLACK, TextSymbol.HorizontalAlignment.CENTER, TextSymbol.VerticalAlignment.BOTTOM ) val textGraphic = Graphic(geocodeResult.displayLocation, textSymbol) graphicsOverlay.graphics.add(textGraphic) // create a graphic to display the location as a red square val simpleMarkerSymbol = SimpleMarkerSymbol(SimpleMarkerSymbol.Style.SQUARE, Color.RED, 12.0f) val markerGraphic = Graphic(geocodeResult.displayLocation, geocodeResult.attributes, simpleMarkerSymbol) graphicsOverlay.graphics.add(markerGraphic) }
-
Call
set
onViewpoint Center Async map
to display the two graphics at the proper location on the map.View MainActivity.ktUse dark colors for code blocks 169 170 171 172 173 174 175 176Add line. // create a graphic to display the location as a red square val simpleMarkerSymbol = SimpleMarkerSymbol(SimpleMarkerSymbol.Style.SQUARE, Color.RED, 12.0f) val markerGraphic = Graphic(geocodeResult.displayLocation, geocodeResult.attributes, simpleMarkerSymbol) graphicsOverlay.graphics.add(markerGraphic) mapView.setViewpointCenterAsync(geocodeResult.displayLocation)
-
Click Run > Run > app to run the app.
You should see a search box on the top left of the map. Search for an address by entering an address and press Return on the keyboard. The result of the search should display on the map as a red square.
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: