Search code examples
javaandroidmapboxmapbox-android

Make Mapbox markers clickable and return the ID of the marker


So I've made a MapActivity which shows a MapBox map.

Then I load in all my markers(pins, which are eventually Point objects with longitude and latitude) from the database into a List< Features > markerCoordinates. markerCoordinates is then given through GeoJsonSource().

Now all my markers are displayed on the map.

Now I can't figure out how to make a marker clickable, and when clicked I need to obtain the ID of the marker so I can later on redirect to another Activity and then load in all data based on that ID. This ID of the pin needs to be the same as the ID from the database.

Mapbox Documentation doesn't really helped me out with this problem.

Does any one know how to implement this?

MapActivity.java

public class MapActivity extends AppCompatActivity {
    private MapView mapView;
    DatabaseHelper myDb;

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_moments:
                    Intent intent = new Intent(MapActivity.this, MapActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                    startActivity(intent);
                    break;

                case R.id.navigation_addmoment:
                    Intent intent2 = new Intent(MapActivity.this, AddMomentActivity.class);
                    intent2.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                    startActivity(intent2);
                    break;
            }
            return false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    myDb = new DatabaseHelper(this);

    Mapbox.getInstance(this, "pk.eyJ1IjoiaGlqYWNrbWFuaWFjIiwiYSI6ImNqdWlyb3E3NzE5bjc0Zm9lOHpta3AzajMifQ.ithKXW2RvhRzlPqXWBexyg");

    setContentView(R.layout.activity_map);
    BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
    navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

    mapView = findViewById(R.id.mapView);
    mapView.onCreate(savedInstanceState);
    mapView.getMapAsync(new OnMapReadyCallback() {

        @Override
        public void onMapReady(@NonNull MapboxMap mapboxMap) {
            mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
                @Override
                public void onStyleLoaded(@NonNull Style style) {

                    // Importing markers from database
                    List<Feature> markerCoordinates = new ArrayList<>();

                    loadPins(markerCoordinates);

                    // Adding markers on the map
                    style.addSource(new GeoJsonSource("source-id",
                            FeatureCollection.fromFeatures(markerCoordinates)));

                    // Some styling below
                    style.addImage("marker-icon-id",
                            BitmapFactory.decodeResource(
                                    MapActivity.this.getResources(), R.drawable.mapbox_marker_icon_default));

                    SymbolLayer symbolLayer = new SymbolLayer("layer-id", "source-id");
                    symbolLayer.withProperties(
                            PropertyFactory.iconImage("marker-icon-id")
                    );
                    style.addLayer(symbolLayer);
                }
            });
        }
    });
}

// Switch from map to moments
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.header_items, menu);
    final MenuItem listItem = menu.findItem(R.id.list_menu);
    listItem.setVisible(true);

    listItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            Intent intent = new Intent(MapActivity.this, MomentsActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
            startActivity(intent);
            return true;
        }
    });

    return true;
}

// Reading the Database, appending each row to allMarkers
public void loadPins(List<Feature> allMarkers) {
    Cursor res = myDb.getAllData();
    if(res.getCount() == 0) {
        // Error message
        return;
    }

    while(res.moveToNext()) {
        double longitude = Double.parseDouble(res.getString(4));
        double latitude = Double.parseDouble(res.getString(5));

        if(longitude == 0 || latitude == 0) {
            continue;
        } else {
            allMarkers.add(Feature.fromGeometry(
                    Point.fromLngLat(
                            longitude,
                            latitude
                    )
            ));
        }
    }
}

@Override
public void onStart() {
    super.onStart();
    mapView.onStart();
}

@Override
public void onResume() {
    super.onResume();
    mapView.onResume();
}

@Override
public void onPause() {
    super.onPause();
    mapView.onPause();
}

@Override
public void onStop() {
    super.onStop();
    mapView.onStop();
}

@Override
public void onLowMemory() {
    super.onLowMemory();
    mapView.onLowMemory();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mapView.onDestroy();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mapView.onSaveInstanceState(outState);
}

}


Solution

  • First, you should implement the onMapClick or onMapLongClick methods, so that you can handle all map clicks and retrieve the data you need.
    The steps to get the marker Id on every click are roughly these:

    • Check whether the click was on a marker or elsewhere.

      You can do this by querying the source layer (your GeoJsonSource) and checking whether there is a feature nearby the clicked spot.

    • If a feature was found, get the property you need.

      You could use feature.getProperties() to get all the properties or feature.getStringProperty("name_of_the_property") to get a specific one. See more here.

    Check this example to see how to implement all of this.