I'm attempting to show a route on a map for two specified points, with the end goal of generating step-by-step directions. I'm using the Directions API provided by MapBox and have structured my code based off of this example.
The map appears to load as expected and there are no errors in regards to displaying the map, however there is no route/line present for the specified call, or anywhere on the map for that matter.
I have attempted to use different origins and destinations however still fail to generate the expected result as demonstrated in the example provided.
Code:
@SuppressWarnings("deprecation")
public class MainActivity extends AppCompatActivity implements
OnMapReadyCallback, PermissionsListener, View.OnClickListener, MapboxMap.OnMapClickListener, MapboxMap.OnMarkerClickListener {
private MapView mapView;
private MapboxMap mapboxMap;
private static final String TAG = "MainActivity";
private MapboxDirections client;
private DirectionsRoute currentRoute;
private static final String ROUTE_LAYER_ID = "route-layer-id";
private static final String ROUTE_SOURCE_ID = "route-source-id";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Mapbox access token is configured here.
Mapbox.getInstance(this, getString(R.string.mapbox_access_token));
setContentView(R.layout.activity_main);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.addOnMapClickListener(this);
mapboxMap.setStyle(Style.MAPBOX_STREETS,
new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
enableLocationComponent(style);
Point origin = Point.fromLngLat(-3.588098, 37.176164);
Point destination = Point.fromLngLat(-3.601845, 37.184080);
initSource(style);
initLayers(style);
getRoute(origin, destination);
}
});
mapboxMap.setOnMarkerClickListener(this);
}
private void initLayers(@NonNull Style loadedMapStyle) {
LineLayer routeLayer = new LineLayer(ROUTE_LAYER_ID, ROUTE_SOURCE_ID);
routeLayer.setProperties(
lineCap(Property.LINE_CAP_ROUND),
lineJoin(Property.LINE_JOIN_ROUND),
lineWidth(5f),
lineColor(Color.parseColor("#009688"))
);
loadedMapStyle.addLayer(routeLayer);
}
private void initSource(@NonNull Style loadedMapStyle) {
loadedMapStyle.addSource(new GeoJsonSource(ROUTE_SOURCE_ID,
FeatureCollection.fromFeatures(new Feature[] {})));
}
private void getRoute(Point origin, Point destination) {
client = MapboxDirections.builder()
.origin(origin)
.destination(destination)
.overview(DirectionsCriteria.OVERVIEW_FULL)
.profile(DirectionsCriteria.PROFILE_DRIVING)
.accessToken(Mapbox.getAccessToken())
.build();
client.enqueueCall(new Callback<DirectionsResponse>() {
@Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
// You can get the generic HTTP info about the response
Timber.d("Response code: " + response.code());
if (response.body() == null) {
Timber.e("No routes found, make sure you set the right user and access token.");
return;
} else if (response.body().routes().size() < 1) {
Timber.e("No routes found");
return;
}
// Get the directions route
currentRoute = response.body().routes().get(0);
// Make a toast which displays the route's distance
/*Toast.makeText(MainActivity.this, String.format(
getString(R.string.directions_activity_toast_message),
currentRoute.distance()), Toast.LENGTH_SHORT).show();*/
if (mapboxMap != null) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// Retrieve and update the source designated for showing the directions route
GeoJsonSource source = style.getSourceAs(ROUTE_SOURCE_ID);
// Create a LineString with the directions route's geometry and
// reset the GeoJSON source for the route LineLayer source
if (source != null) {
Timber.d("onResponse: source != null");
source.setGeoJson(FeatureCollection.fromFeature(
Feature.fromGeometry(LineString.fromPolyline(currentRoute.geometry(), PRECISION_6))));
}
}
});
}
}
@Override
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
Timber.e("Error: " + throwable.getMessage());
Toast.makeText(MainActivity.this, "Error: " + throwable.getMessage(),
Toast.LENGTH_SHORT).show();
}
});
}
Ready to get started? Create a free account to start building with Mapbox. Use the mapbox-gl-directions plugin to show results from the Mapbox Directions API. Click the map to add an origin and destination, and use the toggle to switch among the available routing profiles.
Mapbox Temporary Geocoding API Restrictions and Pricing Mapbox's Temporary Geocoding API is free for up to 100,000 requests per month. Prices start at $0.75/1,000 after that.
While both Google Map and Mapbox APIs are providing great features and functionalities to the users, although it is difficult to give a verdict about which API is better than the other, the Mapbox API is clearly ahead of Google maps API in terms of performance and customization.
I took your code and basically put it into the Mapbox demo app’s SimpleMapViewActivity
https://docs.mapbox.com/android/maps/examples/create-a-simple-map-view/
The only major difference between your code and my code is that I put this.mapboxMap = mapboxMap;
and mapboxMap.addOnMapClickListener(this);
inside of the OnStyleLoaded()
callback area instead of the onMapReady()
area. That might do the trick for you. Try that and see what happens. I've added the enableLocationComponent()
code and other permission method overrides.
Other than showing the LocationComponent
, I'm not sure how you've adjusted the code in https://docs.mapbox.com/android/java/examples/show-directions-on-a-map/. https://docs.mapbox.com/android/java/examples/show-directions-on-a-map/ should work for you just fine, so maybe you can help me by explaining how you're adjusting https://docs.mapbox.com/android/java/examples/show-directions-on-a-map/.
See my final result: https://imgur.com/a/QJeK0vB
package com.mapbox.mapboxandroiddemo.examples.basics;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.mapbox.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.MapboxDirections;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxandroiddemo.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.mapbox.core.constants.Constants.PRECISION_6;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;
/**
* The most basic example of adding a map to an activity.
*/
public class SimpleMapViewActivity extends AppCompatActivity implements
OnMapReadyCallback, PermissionsListener, View.OnClickListener, MapboxMap.OnMapClickListener, MapboxMap.OnMarkerClickListener {
private MapView mapView;
private static final String TAG = "SimpleMapViewActivity";
private MapboxDirections client;
private DirectionsRoute currentRoute;
private static final String ROUTE_LAYER_ID = "route-layer-id";
private static final String ROUTE_SOURCE_ID = "route-source-id";
private PermissionsManager permissionsManager;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Mapbox access token is configured here.
Mapbox.getInstance(this, getString(R.string.access_token));
setContentView(R.layout.activity_basic_simple_mapview);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
mapboxMap.setStyle(Style.MAPBOX_STREETS,
new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
SimpleMapViewActivity.this.mapboxMap = mapboxMap;
enableLocationComponent(style);
Point origin = Point.fromLngLat(-3.588098, 37.176164);
Point destination = Point.fromLngLat(-3.601845, 37.184080);
initSource(style);
initLayers(style);
getRoute(origin, destination);
mapboxMap.addOnMapClickListener(SimpleMapViewActivity.this);
mapboxMap.setOnMarkerClickListener(SimpleMapViewActivity.this);
}
});
}
private void initLayers(@NonNull Style loadedMapStyle) {
LineLayer routeLayer = new LineLayer(ROUTE_LAYER_ID, ROUTE_SOURCE_ID);
routeLayer.setProperties(
lineCap(Property.LINE_CAP_ROUND),
lineJoin(Property.LINE_JOIN_ROUND),
lineWidth(5f),
lineColor(Color.parseColor("#009688"))
);
loadedMapStyle.addLayer(routeLayer);
}
private void initSource(@NonNull Style loadedMapStyle) {
loadedMapStyle.addSource(new GeoJsonSource(ROUTE_SOURCE_ID,
FeatureCollection.fromFeatures(new Feature[] {})));
}
private void getRoute(Point origin, Point destination) {
client = MapboxDirections.builder()
.origin(origin)
.destination(destination)
.overview(DirectionsCriteria.OVERVIEW_FULL)
.profile(DirectionsCriteria.PROFILE_DRIVING)
.accessToken(Mapbox.getAccessToken())
.build();
client.enqueueCall(new Callback<DirectionsResponse>() {
@Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
// You can get the generic HTTP info about the response
Log.d(TAG, "Response code: " + response.code());
if (response.body() == null) {
Log.d(TAG, "No routes found, make sure you set the right user and access token.");
return;
} else if (response.body().routes().size() < 1) {
Log.d(TAG, "No routes found");
return;
}
// Get the directions route
currentRoute = response.body().routes().get(0);
// Make a toast which displays the route's distance
/*Toast.makeText(SimpleMapViewActivity.this, String.format(
getString(R.string.directions_activity_toast_message),
currentRoute.distance()), Toast.LENGTH_SHORT).show();*/
if (mapboxMap != null) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// Retrieve and update the source designated for showing the directions route
GeoJsonSource source = style.getSourceAs(ROUTE_SOURCE_ID);
// Create a LineString with the directions route's geometry and
// reset the GeoJSON source for the route LineLayer source
if (source != null) {
Log.d(TAG, "onResponse: source != null");
source.setGeoJson(FeatureCollection.fromFeature(
Feature.fromGeometry(LineString.fromPolyline(currentRoute.geometry(), PRECISION_6))));
}
}
});
}
}
@Override
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
Log.d(TAG, "Error: " + throwable.getMessage());
Toast.makeText(SimpleMapViewActivity.this, "Error: " + throwable.getMessage(),
Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onClick(View view) {
}
@SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
// Check if permissions are enabled and if not request
if (PermissionsManager.areLocationPermissionsGranted(this)) {
// Get an instance of the component
LocationComponent locationComponent = mapboxMap.getLocationComponent();
// Activate with options
locationComponent.activateLocationComponent(
LocationComponentActivationOptions.builder(this, loadedMapStyle).build());
// Enable to make component visible
locationComponent.setLocationComponentEnabled(true);
// Set the component's camera mode
locationComponent.setCameraMode(CameraMode.TRACKING);
// Set the component's render mode
locationComponent.setRenderMode(RenderMode.COMPASS);
} else {
permissionsManager = new PermissionsManager(this);
permissionsManager.requestLocationPermissions(this);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show();
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
enableLocationComponent(style);
}
});
} else {
Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();
finish();
}
}
@Override
public boolean onMapClick(@NonNull LatLng point) {
return true;
}
@Override
public boolean onMarkerClick(@NonNull Marker marker) {
return false;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With