Search code examples
androidgoogle-mapsgoogle-maps-markersinfowindow

Google Maps: Different CustomInfowindow for each marker


I have an android application where a MapsActivity is included to display a number of markers using GoogleMaps.

The markers are created through Timestamp objects

Timestamp object attributes

(double lat,lon;
    int stepSum;
    long timeMilli;
    String state=null;)

stored in Firebase Database.

So I retrieve each Timestamp from the database and try to create a marker with those attibutes above. My problem is that when I click a marker the custom info window is being displayed but its the same for all markers. It should show different attributes for different markers.

Why this is happening

In the drawMarkers() method I instantiate a separate infowindow when I am creating a new marker and set that info window to the GoogleMap object with mMap.setInfoWindowAdapter(infoWindow);.

As I result mMap.setInfoWindowAdapter(infoWindow);is called as many times as markers are created and finally only the last infowindow survives. That is the problem but I can't figure out a solution.

How to implement an infowindow that when I click a marker it presents some kind of data and when I am clicking another marker it presents different kind of data (same layout, different attributes).

A valid example also would do.

CustomInfoWindow class

 private class CustomInfoWindow implements GoogleMap.InfoWindowAdapter{

    private String title=null,hour=null,state=null;
    private int steps=0;

    public CustomInfoWindow(){}

    public CustomInfoWindow(String title, String hour, String state, int steps) {
        this.title = title;
        this.hour = hour;
        this.state = state;
        this.steps = steps;
    }

    @Override
    public View getInfoWindow(Marker marker) {
        return null;
    }

    public void setState(String state) {
        this.state = state;
    }

    @Override
    public View getInfoContents(Marker marker) {
        LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
        View root = inflater.inflate(R.layout.marker_infowindow,null);
        TextView titleTextView = (TextView) root.findViewById(R.id.infowindow_title);
        TextView hourTextView = (TextView) root.findViewById(R.id.infowindow_hour);
        TextView stepsTextView = (TextView) root.findViewById(R.id.infowindow_steps);
        TextView stateTextView = (TextView) root.findViewById(R.id.infowindow_state);
        titleTextView.setText(title);
        if (state!=null){
            stateTextView.setText(getApplicationContext().getString(R.string.state)+" "+state);
            stateTextView.setVisibility(View.VISIBLE);
        }
        hourTextView.setText(getApplicationContext().getString(R.string.time)+" "+hour);
        stepsTextView.setText(getApplicationContext().getString(R.string.steps_so__far)+" "+steps);
        return root;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setHour(String hour) {
        this.hour = hour;
    }

    public void setSteps(int steps) {
        this.steps = steps;
    }
}

How markers are drawn

private void drawMarkers(Calendar c){
    String userId = this.user.getAccount().getId();
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);

    final DatabaseReference timestampRef = FirebaseDatabase.getInstance().getReference()
            .child(FirebaseConstant.TIMESTAMPS.toString());
    timestampRef.child(userId).child(""+year).child(""+month).child(""+dayOfMonth)
            .addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    long childCounter=0;
                    for (DataSnapshot timestampSnapshot:dataSnapshot.getChildren()){
                        CustomInfoWindow infoWindow=new CustomInfoWindow();
                        Timestamp temp = timestampSnapshot.getValue(Timestamp.class);
                        if (temp!=null){
                            infoWindow.setTitle(getString(R.string.todays_timestamp));
                            infoWindow.setHour(getFormatedHourFromTimeMilli(temp.getTimeMilli()));
                            infoWindow.setSteps(temp.getStepSum());
                            if (temp.getState()!=null){
                                infoWindow.setState(temp.getState());
                            }
                            mMap.setInfoWindowAdapter(infoWindow);
                            drawTimestamp(temp);
                            infoWindow=null;
                        }
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {}
            });
}

I have read google's tutorial about info windows but couldn't solve my problem.


Solution

  • My solution

    • Create a class that extends GoogleMap.InfoWindowAdapter. That will be your custom infowindow for the whole map.
    • Inside onMapReady() set an implementation of your customInfoWindow object to the GoogleMap object. That will be the one and only infowindow that it will be displayed when a user is clicking a marker from the map.
    • Finally, inside onMapReady() method set an OnMarkerClickListener to the GoogleMap object as well. Your implementation of the GoogleMap.OnMarkerClickListener.onMarkerClick(Marker marker) will only change the content (change the attributes of the infowindow object, call it however you want) of the infowindow, depending on which marker is clicked.