Skip to main content
GuidesAPI ReferenceExamples

What's Nearby Category

|

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.

Nearby gas stations

A searchService = SearchService() is instantiated to carry out searching for selected category's 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. When successful, it passes the non-empty result list to the CustomAdapter to be displayed in a scrollable list of nearby POIs.

MainActivity.kt
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.
showDialog("No results!")
return@onCompleted
}
a
listView.adapter = CustomAdapter(reference, results, imageSize)
decrement()
}

GemError.Cancel ->
{
// The search action was cancelled.
}

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

MainActivity overrides the onCreate function, which checks that internet access is available, initializes the SDK, and requests location permission from the user. When the map is ready (loaded and initialized), it automatically invokes the search.

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

imageSize = resources.getDimension(R.dimen.landmark_image_size).toInt()

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.background_color)
val lateralPadding = resources.getDimension(R.dimen.big_padding).toInt()
listView.setPadding(lateralPadding, 0, lateralPadding, 0)

increment()

SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
if (!isReady) return@onMapDataReady
// Defines an action that should be done after the world map is ready.
search()
}

SdkSettings.onApiTokenRejected = {
/*
The TOKEN you provided in the AndroidManifest.xml file was rejected.
Make sure you provide the correct value, or if you don't have a TOKEN,
check the magiclane.com website, sign up/sign in and generate one.
*/
showDialog("TOKEN REJECTED")
}

// This step of initialization is mandatory if you want to use the SDK without a map.
if (!GemSdk.initSdkWithDefaults(this))
{
// The SDK initialization was not completed.
finish()
}

/*
The SDK initialization completed with success, but for the search action to be executed
properly the app needs permission to get your location.
Not requesting this permission or not granting it will make the search fail.
*/
requestPermissions(this)

if (!Util.isInternetConnected(this))
{
showDialog("You must be connected to the internet!")
}

onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true)
{
override fun handleOnBackPressed()
{
finish()
exitProcess(0)
}
})
}

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).

MainActivity.kt
 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
a
PositionService.getCurrentPosition()?.let {
searchAround(it)
}
}

private fun searchAround(reference: Coordinates) = SdkCall.execute {
this.reference = reference
a
// Cancel any search that is in progress now.
searchService.cancelSearch()
a
// Search around position using the provided search preferences and/or filter.
searchService.searchAroundPosition(EGenericCategoriesIDs.GasStation)
}
note

When no category is selected, the example searches for the closest POIs based on the user actual or simulated location.

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:

MainActivity.kt
/**
* 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>,
private val imageSize: Int
) : RecyclerView.Adapter<CustomAdapter.ViewHolder>()
{
class ViewHolder(view: View) : RecyclerView.ViewHolder(view)
{
val image: ImageView = view.findViewById(R.id.image)
val text: TextView = view.findViewById(R.id.text)
val description: TextView = view.findViewById(R.id.description)
val status: TextView = view.findViewById(R.id.status_text)
val statusDescription: 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.run {
image.setImageBitmap(dataSet[position].imageAsBitmap(imageSize))
text.text = dataSet[position].name
description.text = GemUtil.getLandmarkDescription(dataSet[position], true)
status.text = dist.first
statusDescription.text = dist.second
}
} ?: Unit

override fun getItemCount() = dataSet.size
}