Search Engine
The Mapbox Search SDK for Android is in public preview. All features and workflows are subject to change.
Search engine help users find specific addresses, points of interest (POIs), and places. The Mapbox Search SDK for Android provides the SearchEngine
class for:
Forward geocoding is likely what comes to mind when you think about a typical search experience: for the given String
query a user gets geographic coordinates of an address or place. For example, you can type in Lincoln Memorial
and retrieve the geographic location of a place that matches that query (-77.050,38.889
).
Reverse geocoding is an opposite operation of forward geocoding: for the given geographic coordinates a user gets place names or addresses. For example, turning -77.050, 38.889
into 2 Lincoln Memorial Circle NW
address.
Category search allows you to select a category (for example, restaurants
) and retrieve a list of POIs that belong to that category. For example, if you want to display many restaurants within walking distance of a theater on a map, you can use category search with the restaurants
category.
Integration
The Mapbox Search SDK for Android provides a SearchEngine
class for executing forward geocoding search requests, reverse geocoding search requests, and making category search requests. You can obtain an instance of the engine via the SearchEngine.createSearchEngine(SearchEngineSettings)
function or via the createSearchEngineWithBuiltInDataProviders(SearchEngineSettings)
function to obtain an instance of the engine with history
and favorites
data providers registered by default.
val searchEngine = SearchEngine.createSearchEngine(
SearchEngineSettings(getString(R.string.mapbox_access_token))
)
or
val searchEngine = SearchEngine.createSearchEngineWithBuiltInDataProviders(
SearchEngineSettings(getString(R.string.mapbox_access_token))
)
API type
SearchEngine
factory-functions createSearchEngine()
and createSearchEngineWithBuiltInDataProviders()
accept optional parameter apiType
which defines the search endpoint that will be used for search requests.
There are two types of the ApiType
:
ApiType.GEOCODING
.SearchEngines
created with theGEOCODING
API Type will target the Geocoding API. This is a default API Type for theSearchEngine
.ApiType.SBS
.SearchEngines
created with theSBS
API Type will target the Mapbox Search API.
The Mapbox Search API is in private preview for worldwide coverage and in public preview for Japan. Unless you are part of the private preview program, the Mapbox Search API is only available for Japanese-language queries for locations in Japan.
Learn how to access the Mapbox Search API and make Japanese-language queries for locations in Japan.
Forward geocoding
Forward geocoding allows you to search for places by name.
Forward geocoding in the Search SDK consists of two steps: suggestions search and suggestions selection.
Suggestions search
Options marked with the @Reserved(SBS)
annotation are available in private preview. If you're interested in using these options, contact sales to enable access. If you try to use these options without access, SearchEngine
will ignore them.
When you provide a String
query and set of options, SearchOptions
, to SearchEngine.search()
, it returns a list of suggestions List<SearchSuggestion>
that contain information about an address or a place (including name, categories, description, and type).
val task = searchEngine.search(
"Paris Eiffel Tower",
SearchOptions(limit = 5),
searchCallback
)
Resulting suggestions will be passed to the SearchSuggestionsCallback.onSuggestions()
callback:
val searchCallback = object : SearchSuggestionsCallback {
override fun onSuggestions(suggestions: List<SearchSuggestion>, responseInfo: ResponseInfo) {
val suggestion = suggestions.firstOrNull()
}
override fun onError(e: Exception) {
}
}
Additional information, like geographic coordinates of a place, is not available at this step. To get more information about a suggestion you need to make a suggestion selection.
Suggestion selection
To retrieve more information for a specific suggestion, use the SearchEngine.select()
method:
val selectRequestTask = searchEngine.select(suggestion, selectCallback)
The result of the select operation will be passed to one of the SearchSelectionCallback
callback functions:
val selectCallback = object : SearchSelectionCallback {
override fun onResult(
suggestion: SearchSuggestion,
result: SearchResult,
responseInfo: ResponseInfo
) {
}
override fun onSuggestions(suggestions: List<SearchSuggestion>, responseInfo: ResponseInfo) {
}
override fun onCategoryResult(
suggestion: SearchSuggestion,
results: List<SearchResult>,
responseInfo: ResponseInfo
) {
}
override fun onError(e: Exception) {
}
}
Depending on the type of suggestion, SearchSuggestion.type
, different selection logic is applied:
Suggestion type | Result of select operation | Description |
---|---|---|
SearchResultSuggestion | SearchResult | Suggestion has a place or address associated with it. Search result contains information about geographic coordinates. Source of information: server Result of operation is passed to: SearchSelectionCallback.onResult() |
Category Private preview | List<SearchResult> | Suggestion indicates that the SDK found a category name for category search. Selection of such suggestion results in a category search request with the result being list of POIs. Each search result contains information about geographic coordinates. Source of information: server Result of operation is passed to: SearchSelectionCallback.onCategoryResult() |
Query Private preview | List<SearchSuggestion> | Suggestion indicates that a user has likely misspelled a query during the first step of forward geocoding. Selection of such suggestion results in the same search request from the first step with a changed query. The result of the operation is new list of suggestions. Source of information: server Result of operation is passed to: SearchSelectionCallback.onSuggestions() |
IndexableRecordItem | SearchResult | Suggestion has a place or address associated with it. Search result contains information about geographic coordinates. Source of information: data provider (read more in the Data providers guide) Result of operation is passed to: SearchSelectionCallback.onResult() |
If the passed suggestion is of the type SearchResultSuggestion
or IndexableRecordItem
, then you receive information about coordinates in the SearchSelectionCallback.onResult()
method:
val selectCallback = object : SearchSelectionCallback {
override fun onResult(
suggestion: SearchSuggestion,
result: SearchResult,
responseInfo: ResponseInfo
) {
val coordinates = result.coordinate
}
override fun onSuggestions(suggestions: List<SearchSuggestion>, responseInfo: ResponseInfo) {
}
override fun onCategoryResult(
suggestion: SearchSuggestion,
results: List<SearchResult>,
responseInfo: ResponseInfo
) {
}
override fun onError(e: Exception) {
}
}
A successfully completed SearchEngine.select()
method adds HistoryRecord
, created from SearchResult
, to HistoryDataProvider
by default (read more about history data provider in the Data Providers guide). If you want to turn off the default functionality, specify extra parameter options: SelectOptions
with the following options:
val options = SelectOptions(addResultToHistory = false)
val selectRequestTask = searchEngine.select(suggestion, options, selectCallback)
Batch suggestions selection
You can also select multiple suggestions at once with the SearchEngine.select()
method. The only requirements are:
- All suggestions must originate from the same search request
- All suggestions should be allowed for batch selection
Invoke SearchSuggestion.isBatchResolveSupported
to check if a suggestion can be used for batch selection.
val batchSuggestions = suggestions.filter { it.isBatchResolveSupported }
val selectRequestTask = searchEngine.select(batchSuggestions, multipleSelectCallback)
Provided results will be passed to the SearchMultipleSelectionCallback.onResult()
callback.
val multipleSelectCallback = object : SearchMultipleSelectionCallback {
override fun onResult(
suggestions: List<SearchSuggestion>,
results: List<SearchResult>,
responseInfo: ResponseInfo
) {
}
override fun onError(e: Exception) {
}
}
Forward geocoding with batch selection allows you to get several search results using fewer requests.
Reverse geocoding
When you provide a Point
location and set of options, ReverseGeoOptions
, to ReverseGeocodingSearchEngine
, it returns a list of places, addresses, and POIs List<SearchResult>
.
val task = searchEngine.search(
ReverseGeoOptions(
center = Point.fromLngLat(2.294434, 48.858349)
),
reverseSearchCallback
)
Resulting suggestions will be passed to the SearchCallback.onResults()
callback:
val reverseSearchCallback = object : SearchCallback {
override fun onResults(results: List<SearchResult>, responseInfo: ResponseInfo) {
}
override fun onError(e: Exception) {
}
}
Reverse geocoding allows you to enter a geographic coordinate and receive the name of one or more places that exist at that location.
Category search
Options marked with the @Reserved(SBS)
annotation are available in private preview. If you're interested in using these options, contact sales to enable access. If you try to use these options without access, CategorySearchEngine
will ignore them.
When you provide a String
query and set of options, CategorySearchOptions
, to CategorySearchEngine
, it returns a list of POIs List<SearchResult>
. You can find a list of common category names in the Mapbox Geocoding API documentation.
val task = searchEngine.search(
"cafe",
CategorySearchOptions(limit = 1),
categorySearchCallback
)
Resulting suggestions will be passed to the SearchCallback.onResults()
callback:
val categorySearchCallback = object : SearchCallback {
override fun onResults(results: List<SearchResult>, responseInfo: ResponseInfo) {
}
override fun onError(e: Exception) {
}
}
Category search allows you to look for places that belong to a specified category.
POI metadata in search responses
SearchEngine
might provide POI metadata in search responses. The metadata includes:
- Place's information like phone number, website, open hours
- Average rating and number of reviews
- Parking information
- Place images
This data can be accessed via SearchResult.metadata
. By default, the metadata is available to selected customers only, contact sales team if you are interested in receiving metadata as part of search results.
Add search to an app
This example will show you how to use pre-built UI component to quickly add search to an app.
Open the activity’s XML manifest file. Set permissions and reference the name of the Application you created in the last step:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:theme="@style/AppTheme"> <activityandroid:name=".MainActivity"android:exported="true"> <intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
Open the activity’s XML layout file and add the following view:
<?xml version="1.0" encoding="utf-8"?><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"> <EditTextandroid:id="@+id/query_edit_text"android:layout_width="match_parent"android:layout_height="56dp"android:hint="Where to?"android:paddingHorizontal="16dp"/> <com.mapbox.search.ui.view.SearchResultsViewandroid:id="@+id/search_results_view"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="56dp"android:paddingVertical="16dp"/></FrameLayout>
Create a new Activity or open an existing Activity and add the code below:
import android.Manifest.permissionimport android.content.Contextimport android.content.pm.PackageManagerimport android.os.Bundleimport android.text.Editableimport android.text.TextWatcherimport android.widget.EditTextimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport androidx.core.app.ActivityCompatimport androidx.core.content.ContextCompatimport com.mapbox.search.ApiTypeimport com.mapbox.search.ResponseInfoimport com.mapbox.search.SearchEngineimport com.mapbox.search.SearchEngineSettingsimport com.mapbox.search.ServiceProviderimport com.mapbox.search.offline.OfflineResponseInfoimport com.mapbox.search.offline.OfflineSearchEngineimport com.mapbox.search.offline.OfflineSearchEngineSettingsimport com.mapbox.search.offline.OfflineSearchResultimport com.mapbox.search.record.HistoryRecordimport com.mapbox.search.result.SearchResultimport com.mapbox.search.result.SearchSuggestionimport com.mapbox.search.ui.view.CommonSearchViewConfigurationimport com.mapbox.search.ui.view.DistanceUnitTypeimport com.mapbox.search.ui.view.SearchResultsView class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main) val accessToken = getString(R.string.mapbox_access_token) val queryEditText = findViewById<EditText>(R.id.query_edit_text)val searchResultsView = findViewById<SearchResultsView>(R.id.search_results_view)searchResultsView.initialize(SearchResultsView.Configuration(commonConfiguration = CommonSearchViewConfiguration(DistanceUnitType.IMPERIAL))) val searchEngine = SearchEngine.createSearchEngineWithBuiltInDataProviders(apiType = ApiType.GEOCODING,settings = SearchEngineSettings(accessToken)) val offlineSearchEngine = OfflineSearchEngine.create(OfflineSearchEngineSettings(accessToken)) val searchEngineUiAdapter = SearchEngineUiAdapter(view = searchResultsView,searchEngine = searchEngine,offlineSearchEngine = offlineSearchEngine,) searchEngineUiAdapter.addSearchListener(object : SearchEngineUiAdapter.SearchListener { private fun showToast(message: String) {Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show()} override fun onSuggestionsShown(suggestions: List<SearchSuggestion>, responseInfo: ResponseInfo) {// not implemented} override fun onCategoryResultsShown(suggestion: SearchSuggestion,results: List<SearchResult>,responseInfo: ResponseInfo) {// not implemented} override fun onOfflineSearchResultsShown(results: List<OfflineSearchResult>, responseInfo: OfflineResponseInfo) {// not implemented} override fun onSuggestionSelected(searchSuggestion: SearchSuggestion): Boolean {return false} override fun onSearchResultSelected(searchResult: SearchResult, responseInfo: ResponseInfo) {showToast("SearchResult clicked: ${searchResult.name}")} override fun onOfflineSearchResultSelected(searchResult: OfflineSearchResult, responseInfo: OfflineResponseInfo) {showToast("OfflineSearchResult clicked: ${searchResult.name}")} override fun onError(e: Exception) {showToast("Error happened: $e")} override fun onHistoryItemClick(historyRecord: HistoryRecord) {showToast("HistoryRecord clicked: ${historyRecord.name}")} override fun onPopulateQueryClick(suggestion: SearchSuggestion, responseInfo: ResponseInfo) {queryEditText.setText(suggestion.name)} override fun onFeedbackItemClick(responseInfo: ResponseInfo) {// not implemented}}) queryEditText.addTextChangedListener(object : TextWatcher { override fun onTextChanged(s: CharSequence, start: Int, before: Int, after: Int) {searchResultsView.search(s.toString())} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {// not implemented} override fun afterTextChanged(e: Editable) { /* not implemented */ }}) if (!isPermissionGranted(permission.ACCESS_FINE_LOCATION)) {ActivityCompat.requestPermissions(this,arrayOf(permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION),PERMISSIONS_REQUEST_LOCATION)}} private companion object { private const val PERMISSIONS_REQUEST_LOCATION = 0 fun Context.isPermissionGranted(permission: String): Boolean {return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED}}}
Run your application and you will see a functional search UI. Begin typing in the search bar to see results: