I'm trying to show a MapView in an emulator in Android Studios, but when I try to run the activity, the MapView won't show up. I have tried to install the right SDKs from the SDK Manager and think I have the correct emulator to run the MapView. Please let me know what else I can try to have the MapView work. Thank you!
Pixel 5
AVD Manager
SDK Manager
activity_business_location.xml
<com.google.android.gms.maps.MapView
android:id="#+id/businessLocationMapView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
android:contentDescription="#string/business_location_map"/>
BusinessLocationActivity.kt
class BusinessLocationActivity : AppCompatActivity() {
lateinit var jobService : JobService
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
private var currentLocation: Location? = null
private lateinit var placesService: PlacesService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_business_location)
jobService = intent.extras!!.get("jobService") as JobService
placesService = PlacesService.create()
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
setupLocationRequestAndCallback()
getLocationUpdates()
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setTitle("Locate ${jobService.jobName}")
}
private fun setupLocationRequestAndCallback() {
locationRequest = LocationRequest.create().apply {
interval = 100
fastestInterval = 50
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
maxWaitTime= 10
}
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
currentLocation = locationResult.lastLocation
Log.e("Current Location", currentLocation.toString())
getBusinessesNearby()
// add this so location updates isn't running continuously
// only need to run once to get current users location
val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback)
removeTask.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("BusinessLocation", "Location Callback removed.")
} else {
Log.d("BusinessLocation", "Failed to remove Location Callback.")
}
}
}
}
}
private fun getLocationUpdates() {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper()!!)
}
fun getBusinessesNearby() {
val apiKey = getString(R.string.PLACES_API_KEY)
placesService.nearbyPlaces(
apiKey = apiKey,
location = "${currentLocation?.latitude},${currentLocation?.longitude}",
radiusInMeters = 80467,
keyword = jobService.jobName
).enqueue(
object : Callback<NearbyPlacesResponse> {
override fun onFailure(call: Call<NearbyPlacesResponse>, t: Throwable) {
Log.e("BusinessLocation", "Failed to get nearby places", t)
}
override fun onResponse(
call: Call<NearbyPlacesResponse>,
response: Response<NearbyPlacesResponse>
) {
if (!response.isSuccessful) {
Log.e("BusinessLocation", "Failed to get nearby places")
return
}
val places = response.body()?.results ?: emptyList()
Log.e("Places Count: ", places.size.toString())
for (place in places) {
Log.e("Place: ", place.toString())
}
}
}
)
}
}
NearbyPlacesResponse.kt
data class NearbyPlacesResponse(
#SerializedName("results") val results: List<Place>
)
PlacesService.kt
interface PlacesService {
#GET("nearbysearch/json")
fun nearbyPlaces(
#Query("key") apiKey: String,
#Query("location") location: String,
#Query("radius") radiusInMeters: Int,
#Query("keyword") keyword: String
): Call<NearbyPlacesResponse>
companion object {
private const val ROOT_URL = "https://maps.googleapis.com/maps/api/place/"
fun create(): PlacesService {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BODY
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
val converterFactory = GsonConverterFactory.create()
val retrofit = Retrofit.Builder()
.baseUrl(ROOT_URL)
.client(okHttpClient)
.addConverterFactory(converterFactory)
.build()
return retrofit.create(PlacesService::class.java)
}
}
}
Did you follow the documentation? I think it is well explained how to config it.
https://developers.google.com/maps/documentation/android-sdk/map
You need to add an Maps API Key to your project and do some other configs:
https://developers.google.com/maps/documentation/android-sdk/config
Here is how you create your Maps API Key:
https://developers.google.com/maps/documentation/android-sdk/get-api-key
Related
I'm using FusedLocationProvider in my app and I noticed that when my app is in the background and I start some other app that contains Google Map my original app starts receiving location updates extremely fast (like 1 update per second) despite setting up the fastest interval.
I know that I should unregister when going to background etc but this is not the case here.
Any ideas why this might happen or where I can report it to Google?
This is the activity I start it from (I've removed couple of permissions check just for the visibility)
The full repo can be found here
class MainActivity : AppCompatActivity() {
private val locationController by lazy { LocationController.getInstance(applicationContext) }
lateinit var button: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button = findViewById(R.id.button)
button.setOnClickListener {
if (locationController.isStarted) {
locationController.stop()
button.text = "START LOCATION UPDATES"
} else {
locationController.start()
button.text = "STOP LOCATION UPDATED"
}
}
}
And the LocationController looks like this:
class LocationController(context: Context) {
companion object {
#Volatile private var INSTANCE: LocationController? = null
fun getInstance(context: Context): LocationController {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: LocationController(context).also { INSTANCE = it }
}
}
}
private val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
private val locationRequest by lazy {
LocationRequest.create()
.setInterval(INTERVAL_MILLIS)
.setFastestInterval(FASTEST_INTERVAL_MILLIS)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
}
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
Log.d("boom", "onLocationResult! ${locationResult.lastLocation}")
}
override fun onLocationAvailability(locationAvailability: LocationAvailability) {
super.onLocationAvailability(locationAvailability)
}
}
var isStarted: Boolean = false
#SuppressLint("MissingPermission")
fun start() {
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
.addOnSuccessListener {
Log.d("boom", "requestLocationUpdates success!")
}
isStarted = true
}
fun stop() {
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
.addOnSuccessListener {
Log.d("boom", "removeLocationUpdates success!")
}
isStarted = false
}
The constant values I experience it with are:
const val INTERVAL_MILLIS = 30_000L
const val FASTEST_INTERVAL_MILLIS = 10_000L
This question reflects back to a previous question: Show multiple registered user`s location on the same map (Android Studio, Firebase, Kotlin)
My main problem is that I have created a chatting app in Android Studio, and also added a map activity, using Google Api. I am using Firebase Realtime Database, and this is how my tree currently looks like:
I want the "userlocation" appear under each of my registered user, so all registered user`s location will will appear on my Google Map as a marker.
Here is my MapsActivity:
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
companion object {
var currentUser: User? = null
val TAG = "MapsActivity"
}
private lateinit var map: GoogleMap
private val LOCATION_PERMISSION_REQUEST = 1
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
private fun getLocationAccess() {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
map.isMyLocationEnabled = true
getLocationUpdates()
startLocationUpdates()
}
else
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST)
}
private fun getLocationUpdates() {
locationRequest = LocationRequest()
locationRequest.interval = 30000
locationRequest.fastestInterval = 20000
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
if (locationResult.locations.isNotEmpty()) {
val location = locationResult.lastLocation
// val uid = FirebaseAuth.getInstance().currentUser?.uid
// val rootRef = FirebaseFirestore.getInstance()
// val usersRef = rootRef.collection("users")
// val uidRef = uid?.let { usersRef.document(it) }
// if (uidRef != null) {
// uidRef.get()
// .addOnSuccessListener { document ->
// if (document != null) {
// val latitude = document.getDouble("latitude")
// val longitude = document.getDouble("longitude")
// Log.d(TAG, ", " + location.latitude + location.longitude)
// } else {
// Log.d(TAG, "No such document")
// }
// }
// .addOnFailureListener { exception ->
// Log.d(TAG, "get failed with ", exception)
// }
// }
lateinit var databaseRef: DatabaseReference
databaseRef = Firebase.database.reference
val locationlogging = LocationLogging(location.latitude, location.longitude)
databaseRef.child("/userlocation").setValue(locationlogging)
.addOnSuccessListener {
Toast.makeText(applicationContext, "Locations written into the database", Toast.LENGTH_LONG).show()
}
.addOnFailureListener {
Toast.makeText(applicationContext, "Error occured while writing your location to the database", Toast.LENGTH_LONG).show()
}
}
}
}
}
#SuppressLint("MissingPermission")
private fun startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(locationRequest,locationCallback, null)
}
#SuppressLint("MissingPermission")
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode == LOCATION_PERMISSION_REQUEST) {
if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
map.isMyLocationEnabled = true
} else { Toast.makeText(this, "User has not granted location access permission", Toast.LENGTH_LONG).show()
finish()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
}
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
getLocationAccess()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.nav_menu_map, menu)
return super.onCreateOptionsMenu(menu)
}
I commented out some of the codes as I wasn`t able to implement it properly. When I ran the code, the latitude and longitude appeared in my Logcat, but in my Realtime database, it wiped out all my data under /users and it was replaced by the latitude and longitude.
Here is my LocationLogging:
import com.google.firebase.database.IgnoreExtraProperties
#IgnoreExtraProperties
data class LocationLogging(
var Latitude: Double? = 0.0,
var Longitude: Double? = 0.0
)
I am looking to find an easy way, which puts the coordinates into my Firebase Realtime Database under each of my registered users, and show all locations on the map at the same time.
You can get the current user with the firebase auth SDK and change the path where you save the data to save it under the user path. You would need to change this part of your code:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
lateinit var databaseRef: DatabaseReference
databaseRef = Firebase.database.reference
val locationlogging = LocationLogging(location.latitude, location.longitude)
databaseRef.child("users").child(user.getUid()).child("userlocation").setValue(locationlogging)
.addOnSuccessListener {
Toast.makeText(applicationContext, "Locations written into the database", Toast.LENGTH_LONG).show()
}
.addOnFailureListener {
Toast.makeText(applicationContext, "Error occured while writing your location to the database", Toast.LENGTH_LONG).show()
}
I am new to Android Dagger-Hilt and I found it useful for my project. However, recently I want to use this concept to get my ServerConnection class to become Singleton across different view (fragment and activity). How can I achieve that?
I had tried to approach below but I can't get it Singleton as it will create 2 ServerConnection instance in my fragment/activity view. Where had I do wrong?
Current approach
AppModule.kt
#Singleton
#Provides
fun provideSocketConnection(tokenDao: TokenDao) : ServerConnection{
val token = runBlocking(Dispatchers.IO) { tokenDao.find() }
val tok = token!!.token
val refreshToken = token.refresh_token
return ServerConnection(URL)
}
ServerConnection.kt
class ServerConnection(url: String) {
enum class ConnectionStatus {
DISCONNECTED, CONNECTED
}
interface ServerListener {
fun onNewMessage(message: String?)
fun onStatusChange(status: ConnectionStatus?)
}
private var mWebSocket: WebSocket? = null
private val mClient: OkHttpClient
private val mServerUrl: String
private var mMessageHandler: Handler? = null
private var mStatusHandler: Handler? = null
private var mListener: ServerListener? = null
init {
mClient = OkHttpClient.Builder()
.readTimeout(3, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
mServerUrl = url
}
private inner class SocketListener : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
val m = mStatusHandler!!.obtainMessage(0, ConnectionStatus.CONNECTED)
mStatusHandler!!.sendMessage(m)
}
override fun onMessage(webSocket: WebSocket, text: String) {
val m = mMessageHandler!!.obtainMessage(0, text)
mMessageHandler!!.sendMessage(m)
}
override fun onClosed(
webSocket: WebSocket,
code: Int,
reason: String
) {
val m =
mStatusHandler!!.obtainMessage(0, ConnectionStatus.DISCONNECTED)
mStatusHandler!!.sendMessage(m)
}
override fun onFailure(
webSocket: WebSocket,
t: Throwable,
response: Response?
) {
disconnect()
}
}
fun connect(listener: ServerListener?) {
val request = Request.Builder()
.url(mServerUrl)
.build()
mWebSocket = mClient.newWebSocket(request, SocketListener())
mListener = listener
mMessageHandler =
Handler(Handler.Callback { msg: Message ->
mListener?.onNewMessage(msg.obj as String)
true
})
mStatusHandler = Handler(Handler.Callback { msg: Message ->
mListener!!.onStatusChange(msg.obj as ConnectionStatus)
true
})
}
fun disconnect() {
mWebSocket?.cancel()
mListener = null
mMessageHandler?.removeCallbacksAndMessages(null)
mStatusHandler?.removeCallbacksAndMessages(null)
}
fun sendMessage(message: String?) {
mWebSocket!!.send(message!!)
}
}
View (Fragment/Activity)
#AndroidEntryPoint
class RoomFragment : Fragment(), ServerConnection.ServerListener {
#Inject lateinit var socketConnection: ServerConnection
}
You need to annotate your AppModule.kt class with #InstallIn(SinggltonComponent::class).
To know more about the hilt component, check this detail, here.
So, this is my first time using architecture components in Android. I'm trying to create a ViewModel that will keep returning the latest location which can be used by UI elements. I've created a viewModel like this:
class LocationViewModel(application: Application) : AndroidViewModel(application) {
val currentLocation = MutableLiveData<Location?>()
init {
val ctx = getApplication<Application>().applicationContext
val fusedLocationProvider = LocationServices.getFusedLocationProviderClient(ctx)
val locationRequest = LocationRequest.create()
locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
locationRequest.interval = 5000
locationRequest.fastestInterval = 2000
val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
val client = LocationServices.getSettingsClient(ctx)
client.checkLocationSettings(builder.build()).addOnFailureListener {
currentLocation.postValue(null)
}
val locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult?) {
super.onLocationResult(p0)
p0 ?: return
currentLocation.postValue(p0.lastLocation)
}
}
fusedLocationProvider.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
}
And I observe this ViewModel in an activity, like so
class MainActivity : AppCompatActivity() {
private lateinit var locationText: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
locationText = findViewById(R.id.locationText)
val location = ViewModelProviders.of(this)[LocationViewModel::class.java]
location.currentLocation.observe(this, Observer { resutlLocation: Location? ->
locationText.text =
if (resutlLocation != null) "Lat: ${resutlLocation.latitude} Long: ${resutlLocation.longitude}" else "Null"
})
}
}
The TextView doesn't even gets updated once. How things like these should be done? What Am I doing wrong?
In View View model create function like this.
fun initdata() {
val ctx = getApplication<Application>().applicationContext
val fusedLocationProvider = LocationServices.getFusedLocationProviderClient(ctx)
val locationRequest = LocationRequest.create()
locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
locationRequest.interval = 5000
locationRequest.fastestInterval = 2000
val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
val client = LocationServices.getSettingsClient(ctx)
client.checkLocationSettings(builder.build()).addOnFailureListener {
currentLocation.postValue(null)
}
val locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult?) {
super.onLocationResult(p0)
p0 ?: return
currentLocation.postValue(p0.lastLocation)
}
}
fusedLocationProvider.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
then use like this
val viewModel = ViewModelProviders.of(this)[LocationViewModel::class.java]
viewModel.initdata()
Edit 1
You can lazy initialize like this way
private val users:MutableLiveData<Location?> by lazy {
MutableLiveData().also {
initdata()
}
}
more details refer ViewModel
I have an android app with a map fragment.
The map displays places and I am looking for a way to add a listener to get that place when the user taps on them.
The most relevant information I found was a suggestion to add a listener for clicks to the map, get the long&lat and then search for a place based on that.
I thought I could do that using FetchPlaceRequest but this also seems to require a placeId in the first place when instantiating.
Am I missing something really basic?
EDIT
The code for the fragment containing the map (I thought implementing PlaceSelectionlistener would do the work)
class MapFragment : Fragment(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener,
PlaceSelectionListener, KoinComponent {
private lateinit var mapViewModel: MapViewModel
private lateinit var map: GoogleMap
private var fusedLocationClient: FusedLocationProviderClient? = null
private var locationRequest: LocationRequest? = null
private var locationCallback: LocationCallback? = null
private val permissionsUtils : PermissionsUtils by inject()
private val preferencesUtils : PreferencesUtils by inject { parametersOf(activity!!.applicationContext)}
private var root : View? = null
private val defaultZoom : Float = 16f
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mapViewModel = ViewModelProviders.of(this).get(MapViewModel::class.java)
root = inflater.inflate(R.layout.fragment_map, container, false)
if (canAccessLocation()) {
initialiseMap(true)
} else {
val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
requestPermissions(permissions, PermissionRequests.FineLocation.value)
}
return root
}
override fun onMarkerClick(p0: Marker?) = false
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
map.setMapStyle(MapStyleOptions
.loadRawResourceStyle(activity!!.applicationContext, preferencesUtils.mapMode))
map.uiSettings.isZoomControlsEnabled = true
if (canAccessLocation()){
map.isMyLocationEnabled = true
map.uiSettings.isMyLocationButtonEnabled = true
}
map.setOnMarkerClickListener(this)
}
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
PermissionRequests.FineLocation.value -> {
val permissionGranted = grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
initialiseMap(permissionGranted)
}
}
}
override fun onPause() {
super.onPause()
fusedLocationClient?.removeLocationUpdates(locationCallback)
}
override fun onResume() {
super.onResume()
requestLocationUpdates()
}
override fun onPlaceSelected(status: Place) {
val toast = Toast.makeText(activity!!.applicationContext,""+ status!!.name + status!!.latLng, Toast.LENGTH_LONG)
toast.setGravity(Gravity.TOP, 0, 0)
toast.show()
}
override fun onError(status: Status) {
Toast.makeText(activity!!.applicationContext,"" + status.toString(), Toast.LENGTH_LONG)
.show()
}
private fun initialiseMap(withLocation: Boolean) {
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
if (!withLocation) {
return
}
requestLocationUpdates()
}
private fun requestLocationUpdates() {
if (fusedLocationClient == null) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity!!.applicationContext)
}
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val locationList = locationResult.locations
if (locationList.size > 0) {
val location = locationList[locationList.size - 1]
val latLng = LatLng(location.latitude, location.longitude)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, defaultZoom))
}
}
}
fusedLocationClient?.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
locationRequest = LocationRequest()
locationRequest?.interval = 1800000
locationRequest?.fastestInterval = 1800000
locationRequest?.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
fusedLocationClient?.lastLocation?.addOnCompleteListener(Activity()) { task ->
if (task.isSuccessful && task.result != null) {
val latLong = LatLng(task.result!!.latitude, task.result!!.longitude)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLong, defaultZoom))
}
}
}
private fun canAccessLocation(): Boolean {
return permissionsUtils.hasPermission(activity!!.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)
}
}
Because you can't manage places that shown on MapView (MapFragment) and it's markers not clickable (and customizable) IMHO better way is to hide "default" place markers via Google Maps styling like in this answer of Jozef:
Create JSON file src\main\res\raw\map_style.json like this:
[
{
featureType: "poi",
elementType: "labels",
stylers: [
{
visibility: "off"
}
]
}
]
Add map style to your GoogleMap
googleMap.setMapStyle(MapStyleOptions.loadRawResourceStyle(getContext(), R.raw.map_style));
and then - get nearby places via Place Search from Google Places API URL request:
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=<LAT_LNG>&types=point_of_interest&radius=<RADIUS_IN_METERS>&sensor=false&key=<YOUR_APP_KEY>
parse it and show desired places on map programmatically as customizable and clickable Google Maps markers. That approach allows to you not only process marker clicks via default onMarkerClick(), but to manage quantity and types of places, marker icons design etc. There is also no need to create a request and process its response every time a user clicks on map.
NB! Nearby URL request returns only 20 places, for load more data you should use string value from next_page_token tag of response and pass it via pagetoken parameter for next request:
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=<LAT_LNG>&types=point_of_interest&radius=<RADIUS_IN_METERS>&sensor=false&key=<YOUR_APP_KEY>&pagetoken=<TOKEN_FOR_NEXT_PAGE_FROM_next_page_token_TAG_OF_RESPONSE>