Skip to main content
GuidesAPI ReferenceExamples

What’s Nearby Category

Estimated reading time: 5 minutes

In this guide you will learn how to search for points of interest (POIs) near the current location looking for a certain type of POIs, like gas stations.

Setup

  1. Get your Magic Lane API key token: if you do not have a token, see the Getting Started guide.
  2. Download the Maps & Navigation SDK for Android archive file.
  3. Download the WhatsNearby project archive file or clone the project with git.
  4. See the Configure Android Example guide.

Run the example

In Android Studio, from the File menu, select Sync Project with Gradle Files.


  1. An android device should be connected via USB cable.
  2. Press SHIFT+F10 to compile, install and run the example on the android device.
  3. A scrollable text list of results is shown of points of interest (POIs) in the gas station category near the current location of the device.

How it works

You can open the MainActivity.kt file to see how to search for POIs of a certain category near the current actual or simulated location.

How it works

private val searchService = SearchService(
onStarted = {
progressBar.visibility = View.VISIBLE
},
onCompleted = onCompleted@{ results, errorCode, _ ->
progressBar.visibility = View.GONE

when (errorCode) {
GemError.NoError -> {
val reference = reference ?: return@onCompleted
if (results.isEmpty()) {
// The search completed without errors, but there were no results found.
showToast("No results!")
return@onCompleted
}
listView.adapter = CustomAdapter(reference, results)
}

GemError.Cancel -> {
// The search action was cancelled.
}
else -> {
// There was a problem at computing the search operation.
showToast("Search service error: ${GemError.getMessage(errorCode)}")
}
}
}
)

A searchService = SearchService() is instantiated to carry out searching for POIs around the current actual or simulated position of the device. The onCompleted listener is defined, which is invoked when the search completes, and checks if there was no error, and that the results are not empty, and in that case, passes the non-empty result list to the CustomAdapter to be displayed in a scrollable list of nearby POIs.

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

listView = findViewById(R.id.list_view)
progressBar = findViewById(R.id.progressBar)
val layoutManager = LinearLayoutManager(this)
listView.layoutManager = layoutManager

val separator = DividerItemDecoration(applicationContext, layoutManager.orientation)
listView.addItemDecoration(separator)

listView.setBackgroundResource(R.color.white)
val lateralPadding = resources.getDimension(R.dimen.bigPadding).toInt()
listView.setPadding(lateralPadding, 0, lateralPadding, 0)

SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
if (!isReady) return@onMapDataReady

// Defines an action that should be done after the world map is ready.
search()
}
SdkSettings.onApiTokenRejected = {
showToast("TOKEN REJECTED")
}
// This step of initialization is mandatory for using the SDK without a map.
if (!GemSdk.initSdkWithDefaults(this)) {
// The SDK initialization was not completed.
finish()
}
/*
The SDK initialization completed successfully, but for the search action
to be executed properly, the app needs permission to get the device location.
Not requesting this permission or not granting it will make the search fail.
*/
requestPermissions(this)

if (!Util.isInternetConnected(this)) {
Toast.makeText(this, "You must be connected to internet!",
Toast.LENGTH_LONG).show()
}
}

MainActivity overrides the onCreate function, which checks that internet access is available, initializes the SDK, and requests location permission from the user. Then, when the map is ready, that is, loaded and initialized, it automatically invokes the search.
The search triggers the onCompleted listener below which passes the resulting list of POIs, if not empty, to a CustomAdapter to be displayed as a scrollable list.

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
PermissionsHelper.onRequestPermissionsResult(
this,
requestCode,
grantResults
)
val result = grantResults[permissions.indexOf(Manifest.permission.ACCESS_FINE_LOCATION)]
if (result != PackageManager.PERMISSION_GRANTED) {
finish()
exitProcess(0)
}
postOnMain { search() }
}
private fun requestPermissions(activity: Activity): Boolean {
val permissions = arrayListOf(
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_NETWORK_STATE
)
return PermissionsHelper.requestPermissions(
REQUEST_PERMISSIONS,
activity,
permissions.toTypedArray()
)
}

Before actually trying a search, it may be necessary to first request location permission for the example app from the user. The onCreate() function requests the permission to access the device location using requestPermissions().

private fun search() = SdkCall.execute {
// If one of the location permissions is granted, we can do the search around action.
val hasPermissions =
PermissionsHelper.hasPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
if (!hasPermissions) return@execute

PositionService().getCurrentPosition()?.let {
searchAround(it)
}
}
private fun searchAround(reference: Coordinates) = SdkCall.execute {
this.reference = reference

// Cancel any search that is in progress now.
searchService.cancelSearch()

// Search around position using the provided search preferences and/ or filter.
searchService.searchAroundPosition(EGenericCategoriesIDs.GasStation)
}

If location permission was given by the user, then the search() function can call the searchAround() function, which cancels the ongoing search in progress, if any, and then starts a search for gas station POIs: searchService.searchAroundPosition(EGenericCategoriesIDs.GasStation) and when the search completes, the searchService.onCompleted listener callback function, defined in the searchService, is invoked to put the results in a scrollable list for display, using a CustomAdapter:

/**
* This custom adapter is made to facilitate the displaying of the data from the model
* and to decide how it is displayed.
*/
class CustomAdapter(private val reference: Coordinates, private val dataSet: ArrayList<Landmark>) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val text: TextView = view.findViewById(R.id.text)
val status: TextView = view.findViewById(R.id.status_text)
val description: TextView = view.findViewById(R.id.status_description)
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.list_item, viewGroup, false)

return ViewHolder(view)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) = SdkCall.execute {
val meters = dataSet[position].coordinates?.getDistance(reference)?.toInt() ?: 0
val dist = getDistText(meters, EUnitSystem.Metric, true)

viewHolder.text.text = dataSet[position].name
viewHolder.status.text = dist.first
viewHolder.description.text = dist.second
} ?: Unit
override fun getItemCount() = dataSet.size
}

Android Examples

Maps SDK for Android Examples can be downloaded or cloned with Git.