Here's the thing:
I have a map with markers on it (managed by a ClusterManager) and I am showing an info window each time they are clicked. I am also fetching their address at the time they are clicked, so once I get it, I call showInfoWindow() on the marker again in order to update it. Problem is that the address won't show up in the info window. Here is my InfoWindowAdapter (I have two views according to the type of the marker that is clicked):
class CabinetInfoWindowAdapter implements GoogleMap.InfoWindowAdapter {
public CabinetInfoWindowAdapter () {
}
#Override
public View getInfoWindow(Marker marker) {
// Use the default info window frame
return null;
}
#Override
public View getInfoContents(Marker marker) {
Cabinet cabinet = clickedCabinetMarker.getCabinet();
Log.i("fttxgr", "info contents, cabinet type: " + cabinet.getType().toString());
switch (cabinet.getType()) {
case ADSL:
case VDSL:
return getCabinetView(cabinet, marker);
case DSLAM:
return getDslamView(cabinet, marker);
default: return null;
}
}
private final View getCabinetView (final Cabinet cabinet, final Marker marker) {
View view = getLayoutInflater().inflate(R.layout.cabinet_info_window, null);
TextView cabinetId = (TextView) view.findViewById(R.id.cabinet_id);
TextView cabinetType = (TextView) view.findViewById(R.id.cabinet_type);
TextView cabinetAddress = (TextView) view.findViewById(R.id.cabinet_address);
TextView cabinetCoordinates = (TextView) view.findViewById(R.id.cabinet_coordinates);
TextView cabinetUserNick = (TextView) view.findViewById(R.id.cabinet_user_nick);
ImageView cabinetImage = (ImageView) view.findViewById(R.id.cabinet_image);
View header = view.findViewById(R.id.header);
cabinetId.setText (cabinet.getId() + " - " + cabinet.getCabinetNumber());
cabinetType.setText (cabinet.getType().toString());
switch (cabinet.getType()) {
case ADSL:
header.setBackgroundColor(getResources().getColor(R.color.adsl_red));
break;
case VDSL:
header.setBackgroundColor(getResources().getColor(R.color.vdsl_green));
break;
}
cabinetCoordinates.setText(cabinet.getCoordinates().toString());
if (cabinet.getImage() == null) {
loadCabinetImage(marker);
} else {
cabinetImage.setImageBitmap(cabinet.getImage());
}
if (cabinet.getUserNick() == null) {
loadCabinetUserNick(cabinet, cabinet.getUserId(), cabinet.getmUserSite(), marker);
} else {
cabinetUserNick.setText("Added by user: " + cabinet.getUserNick());
}
if (cabinet.getAddress() == null) {
loadCabinetAddress(cabinet.getCoordinates().latitude,
cabinet.getCoordinates().longitude, marker);
} else {
cabinetAddress.setText("Address: " + cabinet.getAddress());
}
return view;
}
private final View getDslamView (final Cabinet cabinet, final Marker marker) {
View view = getLayoutInflater().inflate(R.layout.dslam_info_window, null);
TextView dslamId = (TextView) view.findViewById(R.id.dslam_id);
TextView dslamAddress = (TextView) view.findViewById (R.id.dslam_address);
TextView dslamCoordinates = (TextView) view.findViewById (R.id.dslam_coordinates);
dslamId.setText(cabinet.getId() + " - " + cabinet.getCabinetNumber());
dslamCoordinates.setText(cabinet.getCoordinates().toString());
if (cabinet.getAddress() == null) {
Log.i("fttxgr", "address is null");
loadCabinetAddress(cabinet.getCoordinates().latitude,
cabinet.getCoordinates().longitude, marker);
} else {
Log.i("fttxgr", "address is there: " + cabinet.getAddress());
dslamAddress.setText("Address: " + cabinet.getAddress());
}
return view;
}
}
And the loadCabinetAddress() function:
private void loadCabinetAddress (final double lat, final double lng, final Marker marker) {
Geocoder geocoder;
List<Address> addresses;
geocoder = new Geocoder(this, Locale.getDefault());
try {
addresses = geocoder.getFromLocation(lat, lng, 1);
String address = addresses.get(0).getAddressLine(0);
String city = addresses.get(0).getLocality();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String concat = "" +
((address != null) ? address : "") + " - " +
((city != null) ? city : "") + " - " +
((country != null) ? country : "") + " - " +
((postalCode != null) ? postalCode : "");
clickedCabinetMarker.getCabinet().setAddress(concat);
Log.i("fttxgr", "address loaded, showing info window again");
marker.showInfoWindow();
} catch (IOException e) {
e.printStackTrace();
}
}
All the logs indicate that everything goes as expected. So why isn't the info window being updating properly?
P.S. The funny thing is that for the first view (the one returned by getCabinetView()), the update is working! But I also load an image and a user nickname asynchronously, and I call showInfoWindow() three times to update them all.
You can directly use the setOnClusterItemClickListener method if you want to put the infowindow for each item in the cluster of if you want to put a single inforwindow for the whole cluster you can create it using the setOnClusterClickListener method instead of doing all this heavy lifting.
Create a ClusterManager and set the info window using the adapter:
ClusterManager<MarkerItem> clusterMgr = new ClusterManager<MarkerItem>(context, map);
map.setInfoWindowAdapter(clusterMgr.getMarkerManager());
Create infowindowadapter for one of them:
clusterMgr.getMarkerCollection().setOnInfoWindowAdapter(new MyCustomAdapterForItems());
Final piece is mapping the raw Marker object that you'll receive in your custom InfoWindowAdapter's callback to the ClusterItem object(s) that you added to the map in the first place. This can be achieved using the onClusterClick and onClusterItemClick listeners, as follows:
map.setOnMarkerClickListener(clusterMgr);
clusterMgr.setOnClusterItemClickListener(new OnClusterItemClickListener<MarkerItem>() {
#Override
public boolean onClusterItemClick(MarkerItem item) {
clickedClusterItem = item;
return false;
}
});
Related
I am developing an application on android studio that allows users to recommend restaurants and attractions they enjoy. They would submit it through a submission page on my ap. I would like it to store their submission in fire-base and then populate a blank map with a customer marker and the details.
I found a tutorial on adding custom markers to a map using users location that uses firebase but it all done within the code and I am unsure whether adjusting this code to fit my needs would be better than using a different method.
Below is the code used in the tutorial.
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_user_list, container, false);
mUserListRecyclerView = view.findViewById(R.id.user_list_recycler_view);
mMapView = view.findViewById(R.id.user_list_map);
initUserListRecyclerView();
initGoogleMap(savedInstanceState);
setUserPosition();
return view;
}
private void addMapMarkers(){
if(mGoogleMap != null){
if(mClusterManager == null){
mClusterManager = new ClusterManager<ClusterMarker>(getActivity().getApplicationContext(), mGoogleMap);
}
if(mClusterManagerRenderer == null){
mClusterManagerRenderer = new MyClusterMarkerManagerRenderer(
getActivity(),
mGoogleMap,
mClusterManager
);
mClusterManager.setRenderer(mClusterManagerRenderer);
}
for(UserLocation userLocation: mUserLocations){
Log.d(TAG, "addMapMarkers: location: " + userLocation.getGeo_point().toString());
try{
String snippet = "";
if(userLocation.getUser().getUser_id().equals(FirebaseAuth.getInstance().getUid())){
snippet = "This is you";
}
else{
snippet = "Determine route to " + userLocation.getUser().getUsername() + "?";
}
int avatar = R.drawable.cartman_cop; // set the default avatar
try{
avatar = Integer.parseInt(userLocation.getUser().getAvatar());
}catch (NumberFormatException e){
Log.d(TAG, "addMapMarkers: no avatar for " + userLocation.getUser().getUsername() + ", setting default.");
}
ClusterMarker newClusterMarker = new ClusterMarker(
new LatLng(userLocation.getGeo_point().getLatitude(), userLocation.getGeo_point().getLongitude()),
userLocation.getUser().getUsername(),
snippet,
avatar,
userLocation.getUser()
);
mClusterManager.addItem(newClusterMarker);
mClusterMarkers.add(newClusterMarker);
}catch (NullPointerException e){
Log.e(TAG, "addMapMarkers: NullPointerException: " + e.getMessage() );
}
}
mClusterManager.cluster();
setCameraView();
}
}
private void setCameraView() {
// Set a boundary to start
double bottomBoundary = mUserPosition.getGeo_point().getLatitude() - .1;
double leftBoundary = mUserPosition.getGeo_point().getLongitude() - .1;
double topBoundary = mUserPosition.getGeo_point().getLatitude() + .1;
double rightBoundary = mUserPosition.getGeo_point().getLongitude() + .1;
mMapBoundary = new LatLngBounds(
new LatLng(bottomBoundary, leftBoundary),
new LatLng(topBoundary, rightBoundary)
);
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mMapBoundary, 0));}
private void setUserPosition() {
for (UserLocation userLocation : mUserLocations) {
if (userLocation.getUser().getUser_id().equals(FirebaseAuth.getInstance().getUid())) {
mUserPosition = userLocation;
}
I've declared current location latlong and selected location latlong. I want to pass these latlong to onInfoWindowClick().
When I try to use Toast to get the data that I set from marker.setTag(mLatitude) and marker.seTag(mLongitude), It give me the same data only mLongitude. Can anyone help me, please.
This is my code:
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long l) {
if (parent.getItemAtPosition(position).toString() != "-- Pilih ATM --"){
mMap.clear();
String pilih_atm = (String) parent.getItemAtPosition(position);
// Toast.makeText(getActivity(), pilih_atm, Toast.LENGTH_SHORT).show();
SQLiteDatabase db = dbHelper.getReadableDatabase();
cursor = db.rawQuery("SELECT * FROM atm WHERE atm_name = '" + pilih_atm + "'",null);
if (cursor != null){
while (cursor.moveToNext()){
title = cursor.getString(1).toString();
__global_endposition = cursor.getString(2).toString();
String[] exp_endCoordinate = __global_endposition.split(",");
double lat_endposition = Double.parseDouble(exp_endCoordinate[0]);
double lng_endposition = Double.parseDouble(exp_endCoordinate[1]);
LatLng endx = new LatLng(lat_endposition, lng_endposition);
MarkerOptions options = new MarkerOptions();
options.position(endx);
options.title(title);
options.snippet(__global_endposition);
if (title.equals("ATM BNI")){
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
}else if(title.equals("ATM BCA")){
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
}else if(title.equals("ATM Mandiri")){
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW));
}
Marker marker = mMap.addMarker(options);
marker.setTag(mLatitude);
marker.setTag(mLongitude);
mMap.setInfoWindowAdapter(new CustomInfoWindowAdapter(getActivity()));
mMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
// I want to get current location LatLong and selected location LatLong
// I want execute the LatLong on this method
// this just for testing
Toast.makeText(getActivity(), "LatLng: "+marker.getTag()+", "+marker.getTag(), Toast.LENGTH_SHORT).show();
}
});
}
if (!cursor.isClosed()) {
cursor.close();
cursor = null;
}
}
}
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
This is because Marker object has only one Tag object and when you call .setTag() second time, you overrides previously set tag object:
Marker marker = mMap.addMarker(options);
marker.setTag(mLatitude); // tag = mLatitude
marker.setTag(mLongitude); // tag overrides, and now tag = mLongitude
The one of solution is:
Marker marker = mMap.addMarker(options);
marker.setTag("" + mLatitude + "," + mLongitude); // tag now is string: "mLatitude, mLongitude"
i use google maps with get (user) device location (GPS Location) in my android app, and insert into database (SQLite) latitude and longitude and adress !
now i want displayed multiple location with LatLng read from database ... no problem in create marker, but in marker info (country, city ...) only show last inserted location for all markers !
this my code :
private void displayMultiplePoint() {
if (LOCATION_TABLE.size() > 0) {
for (int i = 0; LOCATION_TABLE.size() > i; i++) {
int id = LOCATION_TABLE.get(i).getId();
lat = LOCATION_TABLE.get(i).getLatitude();
lng = LOCATION_TABLE.get(i).getLongitude();
place = LOCATION_TABLE.get(i).getPlace();
rate = LOCATION_TABLE.get(i).getRate();
drawMarker(new LatLng(lat, lng), "city", place, rate);
displayToast(id + "" + place);
}
}
}
private void drawMarker(final LatLng point, final String city, final String place, final float rate) {
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker arg0) {
return null;
}
#Override
public View getInfoContents(Marker arg0) {
View v = null;
try {
v = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
ImageView map_image = (ImageView) v.findViewById(R.id.maps_image);
map_image.setImageResource(R.drawable.runhd);
TextView city_txt = (TextView) v.findViewById(R.id.maps_city);
city_txt.setText(city);
TextView place_txt = (TextView) v.findViewById(R.id.maps_place);
place_txt.setText(place);
RatingBar rate_bar = (RatingBar) v.findViewById(R.id.exercise_display_rate);
rate_bar.setRating(rate);
} catch (Exception ev) {
System.out.print(ev.getMessage());
}
return v;
}
});
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(point);
mMap.addMarker(markerOptions);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(point, 6));
}
i show toast form rowId from lcation table in databse, and displaled 3 row id : 1, 2, 3 but in marker info show last id (id no : 3)
this my fragment :
thank's
I have many solution for your case But at first :
Your fall with setInfoWindowAdapter method it's just invoked one time, So after you iterated your database items and passing info through drawMarker it's just shown the last modified (saved) data from the variables, So i suggest to move it in your for loop (I know it's not a perfect solution) :
for (int i = 0; LOCATION_TABLE.size() > i; i++) {
int id = LOCATION_TABLE.get(i).getId();
lat = LOCATION_TABLE.get(i).getLatitude();
lng = LOCATION_TABLE.get(i).getLongitude();
place = LOCATION_TABLE.get(i).getPlace();
rate = LOCATION_TABLE.get(i).getRate();
drawMarker(new LatLng(lat, lng), "city", place, rate);
displayToast(id + "" + place);
..........
#Override
public View getInfoContents(Marker arg0) {
View v = null;
try {
v = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
ImageView map_image = (ImageView) v.findViewById(R.id.maps_image);
map_image.setImageResource(R.drawable.runhd);
TextView city_txt = (TextView) v.findViewById(R.id.maps_city);
city_txt.setText("city");
TextView place_txt = (TextView) v.findViewById(R.id.maps_place);
place_txt.setText(place);
RatingBar rate_bar = (RatingBar) v.findViewById(R.id.exercise_display_rate);
rate_bar.setRating(rate);
} catch (Exception ev) {
System.out.print(ev.getMessage());
}
return v;
......
}
2nd Solution Using Cursor through your database and use it anywhere (This is will be awesome).
3rd Using Clustering Algorithm in google_maps-utils-example.
The info window is being shown for only last marker because setInfoWindowAdapter() sets info window for the entire map. Inside setInfoWindowAdapter() you need to associate marker argument with corresponding data.
You need to maintain a marker to data map.
Map<Marker, Place> markerToPlaceMap = new HashMap<>();
where, Place is a class to hold city, place, and rating.
class Place {
public String city, place;
public float rating;
}
Note: Please change members to private and implement getters and setters as per your suitability.
Next, Your drawMarker() will change as follows. It needs to add the marker and it's related place to markerToPlace map.
private void drawMarker(final LatLng point, final String city, final String place, final float rate) {
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(point);
Marker marker = mMap.addMarker(markerOptions);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(point, 6));
markerToPlaceMap.put(marker, new Place(city, place, rating));
}
Finally, you will override GoogleMap.setInfoWindowAdapter() and access Place related to a marker for setting corresponding info contents.
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
View v = null;
try {
v = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
ImageView map_image = (ImageView) v.findViewById(R.id.maps_image);
map_image.setImageResource(R.drawable.runhd);
TextView city_txt = (TextView) v.findViewById(R.id.maps_city);
city_txt.setText(markerToPlace.get(marker).city); // <- Check how corresponding place for a marker is fetched and used
TextView place_txt = (TextView) v.findViewById(R.id.maps_place);
place_txt.setText(markerToPlace.get(marker).place);
RatingBar rate_bar = (RatingBar) v.findViewById(R.id.exercise_display_rate);
rate_bar.setRating(markerToPlace.get(marker).rate);
} catch (Exception ev) {
System.out.print(ev.getMessage());
}
return v;
}
});
i Use Cursor through your database and get data rows (and show in Toast)
but
my code change to this :
private void displayMultiplePoint() {
Cursor cursor = DB_HELPER.LOCATION_MARKERS();
if (cursor.moveToFirst()) {
for (int i = 0; cursor.getCount() > i; i++) {
int id = cursor.getInt(cursor.getColumnIndex("id"));
double lat = cursor.getDouble(cursor.getColumnIndex("latitude"));
double lng = cursor.getDouble(cursor.getColumnIndex("longitude"));
String place = cursor.getString(cursor.getColumnIndex("place"));
float rate = cursor.getFloat(cursor.getColumnIndex("rate"));
displayToast(id + ", " + place + rate);
cursor.moveToNext();
drawMarker(new LatLng(lat, lng));
}
cursor.close();
}
}
i get arg0.getId form : (m0, m1, m2 ...)
public View getInfoContents(Marker arg0)
(is unique for each marker) then select data by id where id = arg0
I am trying to create a customised view of my Info Window for which I have made a layout file.
But my data(Lattitude and Longitude ) are in the form a ArrayList.
for (int i = 0; i < list.size(); i++) {
Log.e(getClass().getName(), list.get(i).getFirstName());
double x = list.get(i).getLocationLatLon().getLat();
double y = list.get(i).getLocationLatLon().getLon();
if (x > 90 || x < -90 || y < -180 || y > 180) {
Log.e(getClass().getName(),
"out of range " + Double.toString(x) + " "
+ Double.toString(y));
lng2 = new LatLng(lat, lng);
} else {
Log.e(getClass().getName(),
"In range " + Double.toString(x) + " "
+ Double.toString(y));
lng2 = new LatLng(x, y);
}
InfoClass infoClass= new InfoClass();
infoClass.setName(list.get(i).getFirstName()+" "+list.get(i).getLastName());
infoClass.setCharge(list.get(i).getCharge());
infoClass.setAvailableTime(list.get(i).getTimeAvailable());
infoClass.setServiceCategory(list.get(i).getCategoryName());
infoClass.setServiceName(list.get(i).getServiceName());
finalist.add(infoClass);
theMap.addMarker(new MarkerOptions()
.title(list.get(i).getServiceName())
.position(lng2)
.icon(BitmapDescriptorFactory
.fromResource(entertainment))
.snippet(list.get(i).getFirstName() + " "+ list.get(i).getLastName()) );
theMap.setOnInfoWindowClickListener(this);
}
I am setting my markers according the Latitudes and Longitude in my list and adding the required information to an ArrayList of class InfoClass.
Now when I set setInfoWindowAdapter and pass finalist to my implementation of InfoWindowAdapter.
theMap.setInfoWindowAdapter(new InfoWindow(this, finalist));
my InfoWindow class
public class InfoWindow implements InfoWindowAdapter {
private final View myContentsView;
private LayoutInflater mInflator;
ArrayList<InfoClass> list;
public InfoWindow(Context context, ArrayList<InfoClass> list) {
//Context context = new MainActivity().getApplicationContext();
Context context2= context;
mInflator = LayoutInflater.from(context2);
this.list= list;
myContentsView = mInflator.inflate(R.layout.info_view, null);
}
#Override
public View getInfoWindow(Marker marker) {
return myContentsView;
}
#Override
public View getInfoContents(Marker arg0) {
return null;
}
}
Now here in getInfoWindow method how do I get the get the information for a particular marker as each marker needs to display separate information based on its Location .
I have map view in my fragment. I need to refresh map and add different markers based on condition. So, I should remove last markers from map before add new markers.
Actually, some weeks ago app was working fine and suddenly it happened. My code is like this:
private void displayData(final List<Venue> venueList) {
// Removes all markers, overlays, and polylines from the map.
googleMap.clear();
.
.
.
}
Last time it was working fine (before new Google Map API announce by Android team in I/O 2013). However, after that I adapted my code to use this new API. Now, I don't know why this method googleMap.clear(); doesn't work!
Any suggestion would be appreciated. Thanks
=======
Update
=======
Complete code:
private void displayData(final List<Venue> venueList) {
// Removes all markers, overlays, and polylines from the map.
googleMap.clear();
// Zoom in, animating the camera.
googleMap.animateCamera(CameraUpdateFactory.zoomTo(ZOOM_LEVEL), 2000, null);
// Add marker of user's position
MarkerOptions userIndicator = new MarkerOptions()
.position(new LatLng(lat, lng))
.title("You are here")
.snippet("lat:" + lat + ", lng:" + lng);
googleMap.addMarker(userIndicator);
// Add marker of venue if there is any
if(venueList != null) {
for(int i=0; i < venueList.size(); i++) {
Venue venue = venueList.get(i);
String guys = venue.getMaleCount();
String girls= venue.getFemaleCount();
String checkinStatus = venue.getCan_checkin();
if(checkinStatus.equalsIgnoreCase("true"))
checkinStatus = "Checked In - ";
else
checkinStatus = "";
MarkerOptions markerOptions = new MarkerOptions()
.position(new LatLng(Double.parseDouble(venue.getLatitude()), Double.parseDouble(venue.getLongitude())))
.title(venue.getName())
.snippet(checkinStatus + "Guys:" + guys + " and Girls:" + girls)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_orange_pin));
googleMap.addMarker(markerOptions);
}
}
// Move the camera instantly to where lat and lng shows.
if(lat != 0 && lng != 0)
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), ZOOM_LEVEL));
googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
return null;
}
});
googleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
String str = marker.getId();
Log.i(TAG, "Marker id: " + str);
str = str.substring(1);
int markerId = Integer.parseInt(str);
markerId -= 1; // Because first item id of marker is 1 while list starts at 0
Log.i(TAG, "Marker id " + markerId + " clicked.");
// Ignore if User's marker clicked
if(markerId < 0)
return;
try {
Venue venue = venueList.get(markerId);
if(venue.getCan_checkin().equalsIgnoreCase("true")) {
Fragment fragment = VenueFragment.newInstance(venue);
if(fragment != null)
changeFragmentLister.OnReplaceFragment(fragment);
else
Log.e(TAG, "Error! venue shouldn't be null");
}
} catch(NumberFormatException e) {
e.printStackTrace();
} catch(IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
});
Okay finally I found a replacement way to solve my problem. The interesting problem is when you assign a marker to map, it's id is 'm0'. When you remove it from map and assign new marker you expect the id should be 'm0' but it's 'm1'. Therefore, it showed me the id is not trustable. So I defined List<Marker> markerList = new ArrayList<Marker>(); somewhere in onActivityCreated() of my fragment.
Then changed above code with following one. hope it helps others if they have similar issue with markers.
private void displayData(final List<Venue> venueList) {
Marker marker;
// Removes all markers, overlays, and polylines from the map.
googleMap.clear();
markerList.clear();
// Zoom in, animating the camera.
googleMap.animateCamera(CameraUpdateFactory.zoomTo(ZOOM_LEVEL), 2000, null);
// Add marker of user's position
MarkerOptions userIndicator = new MarkerOptions()
.position(new LatLng(lat, lng))
.title("You are here")
.snippet("lat:" + lat + ", lng:" + lng);
marker = googleMap.addMarker(userIndicator);
// Log.e(TAG, "Marker id '" + marker.getId() + "' added to list.");
markerList.add(marker);
// Add marker of venue if there is any
if(venueList != null) {
for (Venue venue : venueList) {
String guys = venue.getMaleCount();
String girls = venue.getFemaleCount();
String checkinStatus = venue.getCan_checkin();
if (checkinStatus.equalsIgnoreCase("true"))
checkinStatus = "Checked In - ";
else
checkinStatus = "";
MarkerOptions markerOptions = new MarkerOptions()
.position(new LatLng(Double.parseDouble(venue.getLatitude()), Double.parseDouble(venue.getLongitude())))
.title(venue.getName())
.snippet(checkinStatus + "Guys:" + guys + " and Girls:" + girls)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_orange_pin));
marker = googleMap.addMarker(markerOptions);
// Log.e(TAG, "Marker id '" + marker.getId() + "' added to list.");
markerList.add(marker);
}
}
// Move the camera instantly to where lat and lng shows.
if(lat != 0 && lng != 0)
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), ZOOM_LEVEL));
googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
return null;
}
});
googleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
int markerId = -1;
String str = marker.getId();
Log.i(TAG, "Marker id: " + str);
for(int i=0; i<markerList.size(); i++) {
markerId = i;
Marker m = markerList.get(i);
if(m.getId().equals(marker.getId()))
break;
}
markerId -= 1; // Because first item of markerList is user's marker
Log.i(TAG, "Marker id " + markerId + " clicked.");
// Ignore if User's marker clicked
if(markerId < 0)
return;
try {
Venue venue = venueList.get(markerId);
if(venue.getCan_checkin().equalsIgnoreCase("true")) {
Fragment fragment = VenueFragment.newInstance(venue);
if(fragment != null)
changeFragmentLister.OnReplaceFragment(fragment);
else
Log.e(TAG, "Error! venue shouldn't be null");
}
} catch(NumberFormatException e) {
e.printStackTrace();
} catch(IndexOutOfBoundsException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
}
});
}
If you want to clear "all markers, overlays, and polylines from the map", use clear() on your GoogleMap.
Use map.clear() to remove all markers from Google map
Suppose there is an ArrayList of 2 locations. Now, you display markers on the map based on that array. There will be two markers. When you click on the first marker it gives you a marker index m0 and the second is m1.
Say that you refresh location array and now you got an array with 3 locations. You got 3 markers. But when you click on the first one, it gives you marker index m2 (as if it continues counting from the first location arraw) the second is m3 and the third is m4. What you actually want is to make it as m0, m1, m2.
Now, when you build you location array you probably call location.add("you location")... and when you rebuild it (refresh it) you call location.clear() first and then build it again.
SOLUTION:
First, make another dummy array similar to location array and build it in for loop together with a real location array: locaionDummy.add(i) but don't you EVER refresh it - that way it keeps building and you will know how many locations you've ever had from the very beginning.
Second, do something like this (example of setting image) with mIndex as int variable:
void locatePins() {
mIndex = locationDummy.size()-location.size();
for (int i = 0; i < userID.size(); i++) {
LatLng pgLocation = new LatLng(Double.parseDouble(latArr.get(i)), Double.parseDouble(lngArr.get(i)));
myMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
View view = getLayoutInflater().inflate(R.layout.map_marker_info, null);
RelativeLayout markerInfo= view.findViewById(R.id.markerInfo);
TextView name = view.findViewById(R.id.userName);
TextView details = view.findViewById(R.id.userInfo);
ImageView img = view.findViewById(R.id.userImg);
name.setText(marker.getTitle());
details.setText(marker.getSnippet());
img.setImageBitmap (bmImg.get(Integer.parseInt(marker.getId().replaceAll("[^\\d.]", ""))-mIndex));
return view;
}
#Override
public View getInfoContents(Marker marker) {
return null;
}
// ... the rest of the code
}
}
The key is to subtract the real location.size() from a locationDummy.size() to get a number int mIndex that you will subtract later on from marker.getId()
If you need to remove only the markers, and leave other things such as ground overlay,etc there, use:
marker.remove();
or if you have many:
if(markers!=null&&mMap!=null){
for(int i=0;i<markers.size();i++){
markers.get(i).remove();
}
}
where
List<Marker> markers = new ArrayList<>();