Mapbox-navigation-android: Navigation UI crashes when navigation starts (Tutorial: Build a navigation app for Android)

Created on 18 Feb 2019  路  4Comments  路  Source: mapbox/mapbox-navigation-android

Android API:
Test device: Samsung S9+ Android version 9
minSdkVersion 26
targetSdkVersion 28

Mapbox Navigation SDK version:
Tested with 0.28.0 and 0.29.0-SNAPSHOT

Steps to trigger behavior

  1. Follow this tutorial https://docs.mapbox.com/help/tutorials/android-navigation-sdk/

    1. Open the App and click anywhere then press 'Start Navigation' button

Expected behavior

Navigation UI shall start without crashing

Actual behavior

After pressing 'Start Navigation' button, app crashes with the following error:

2019-02-18 11:32:54.097 11702-11702/de.kayten.mapboxnavdemo E/Mbgl-MapChangeReceiver: Exception in onDidFinishLoadingStyle
java.lang.BootstrapMethodError: Exception from call site #0 bootstrap method
at com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager.<init>(AnnotationManager.java:88)
at com.mapbox.mapboxsdk.plugins.annotation.SymbolManager.<init>(SymbolManager.java:79)
at com.mapbox.mapboxsdk.plugins.annotation.SymbolManager.<init>(SymbolManager.java:56)
at com.mapbox.mapboxsdk.plugins.annotation.SymbolManager.<init>(SymbolManager.java:44)
at com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap.initializeNavigationSymbolManager(NavigationMapboxMap.java:583)
at com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap.<init>(NavigationMapboxMap.java:92)
at com.mapbox.services.android.navigation.ui.v5.NavigationView.initializeNavigationMap(NavigationView.java:557)
at com.mapbox.services.android.navigation.ui.v5.NavigationView.access$100(NavigationView.java:68)
at com.mapbox.services.android.navigation.ui.v5.NavigationView$1.onStyleLoaded(NavigationView.java:223)
at com.mapbox.mapboxsdk.maps.MapboxMap.notifyStyleLoaded(MapboxMap.java:839)
at com.mapbox.mapboxsdk.maps.MapboxMap.onFinishLoadingStyle(MapboxMap.java:204)
at com.mapbox.mapboxsdk.maps.MapView$MapCallback.onDidFinishLoadingStyle(MapView.java:1176)
at com.mapbox.mapboxsdk.maps.MapChangeReceiver.onDidFinishLoadingStyle(MapChangeReceiver.java:194)
at com.mapbox.mapboxsdk.maps.NativeMapView.onDidFinishLoadingStyle(NativeMapView.java:1040)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:326)
at android.os.Looper.loop(Looper.java:181)
at android.app.ActivityThread.main(ActivityThread.java:6981)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
Caused by: java.lang.ClassCastException: Bootstrap method returned null
at com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager.<init>(AnnotationManager.java:88)
at com.mapbox.mapboxsdk.plugins.annotation.SymbolManager.<init>(SymbolManager.java:79)
at com.mapbox.mapboxsdk.plugins.annotation.SymbolManager.<init>(SymbolManager.java:56)
at com.mapbox.mapboxsdk.plugins.annotation.SymbolManager.<init>(SymbolManager.java:44)
at com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap.initializeNavigationSymbolManager(NavigationMapboxMap.java:583)
at com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap.<init>(NavigationMapboxMap.java:92)
at com.mapbox.services.android.navigation.ui.v5.NavigationView.initializeNavigationMap(NavigationView.java:557)
at com.mapbox.services.android.navigation.ui.v5.NavigationView.access$100(NavigationView.java:68)
at com.mapbox.services.android.navigation.ui.v5.NavigationView$1.onStyleLoaded(NavigationView.java:223)
at com.mapbox.mapboxsdk.maps.MapboxMap.notifyStyleLoaded(MapboxMap.java:839)
at com.mapbox.mapboxsdk.maps.MapboxMap.onFinishLoadingStyle(MapboxMap.java:204)
at com.mapbox.mapboxsdk.maps.MapView$MapCallback.onDidFinishLoadingStyle(MapView.java:1176)
at com.mapbox.mapboxsdk.maps.MapChangeReceiver.onDidFinishLoadingStyle(MapChangeReceiver.java:194)
at com.mapbox.mapboxsdk.maps.NativeMapView.onDidFinishLoadingStyle(NativeMapView.java:1040)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:326)
at android.os.Looper.loop(Looper.java:181)
at android.app.ActivityThread.main(ActivityThread.java:6981)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
2019-02-18 11:32:54.099 11702-11702/de.kayten.mapboxnavdemo E/libc++abi: terminating with uncaught exception of type jni::PendingJavaException
2019-02-18 11:32:54.099 11702-11702/de.kayten.mapboxnavdemo A/libc: Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 11702 (n.mapboxnavdemo), pid 11702 (n.mapboxnavdemo)

Source code

MapBoxNavDemo.zip

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "de.kayten.mapboxnavdemo"
        minSdkVersion 26
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.mapbox.mapboxsdk:mapbox-android-navigation-ui:0.29.0-SNAPSHOT'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}


// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()

        maven { url 'https://mapbox.bintray.com/mapbox' }
        maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }

    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

MainActivity.java

package de.kayten.mapboxnavdemo;

import android.graphics.BitmapFactory;
import android.os.Bundle;
import java.util.List;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

// classes needed to initialize map
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;

// classes needed to add the location component
import com.mapbox.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.modes.CameraMode;

// classes needed to add a marker
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;

// classes to calculate a route
import com.mapbox.services.android.navigation.ui.v5.NavigationLauncherOptions;
import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.util.Log;

// classes needed to launch navigation UI
import android.view.View;
import android.widget.Button;
import com.mapbox.services.android.navigation.ui.v5.NavigationLauncher;


public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnMapClickListener, PermissionsListener {
    // variables for adding location layer
    private MapView mapView;
    private MapboxMap mapboxMap;
    // variables for adding location layer
    private PermissionsManager permissionsManager;
    private LocationComponent locationComponent;
    // variables for calculating and drawing a route
    private DirectionsRoute currentRoute;
    private static final String TAG = "DirectionsActivity";
    private NavigationMapRoute navigationMapRoute;
    // variables needed to initialize navigation
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Mapbox.getInstance(this, getString(R.string.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.setStyle(getString(R.string.navigation_guidance_day), new Style.OnStyleLoaded() {
            @Override
            public void onStyleLoaded(@NonNull Style style) {
                enableLocationComponent(style);

                addDestinationIconSymbolLayer(style);

                mapboxMap.addOnMapClickListener(MainActivity.this);
                button = findViewById(R.id.startButton);
                button.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        boolean simulateRoute = true;
                        NavigationLauncherOptions options = NavigationLauncherOptions.builder()
                            .directionsRoute(currentRoute)
                            .shouldSimulateRoute(simulateRoute)
                            .build();
                        // Call this method with Context from within an Activity
                        NavigationLauncher.startNavigation(MainActivity.this, options);
                    }
                });
            }
        });
    }

    private void addDestinationIconSymbolLayer(@NonNull Style loadedMapStyle) {
        loadedMapStyle.addImage("destination-icon-id",
            BitmapFactory.decodeResource(this.getResources(), R.drawable.mapbox_marker_icon_default));
        GeoJsonSource geoJsonSource = new GeoJsonSource("destination-source-id");
        loadedMapStyle.addSource(geoJsonSource);
        SymbolLayer destinationSymbolLayer = new SymbolLayer("destination-symbol-layer-id", "destination-source-id");
        destinationSymbolLayer.withProperties(
            iconImage("destination-icon-id"),
            iconAllowOverlap(true),
            iconIgnorePlacement(true)
        );
        loadedMapStyle.addLayer(destinationSymbolLayer);
    }

    @SuppressWarnings( {"MissingPermission"})
    @Override
    public boolean onMapClick(@NonNull LatLng point) {

        Point destinationPoint = Point.fromLngLat(point.getLongitude(), point.getLatitude());
        Point originPoint = Point.fromLngLat(locationComponent.getLastKnownLocation().getLongitude(),
            locationComponent.getLastKnownLocation().getLatitude());

        GeoJsonSource source = mapboxMap.getStyle().getSourceAs("destination-source-id");
        if (source != null) {
            source.setGeoJson(Feature.fromGeometry(destinationPoint));
        }

        getRoute(originPoint, destinationPoint);
        button.setEnabled(true);
        button.setBackgroundResource(R.color.mapboxBlue);
        return true;
    }

    private void getRoute(Point origin, Point destination) {
        NavigationRoute.builder(this)
            .accessToken(Mapbox.getAccessToken())
            .origin(origin)
            .destination(destination)
            .build()
            .getRoute(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.e(TAG, "No routes found, make sure you set the right user and access token.");
                        return;
                    } else if (response.body().routes().size() < 1) {
                        Log.e(TAG, "No routes found");
                        return;
                    }

                    currentRoute = response.body().routes().get(0);

                    // Draw the route on the map
                    if (navigationMapRoute != null) {
                        navigationMapRoute.removeRoute();
                    } else {
                        navigationMapRoute = new NavigationMapRoute(null, mapView, mapboxMap, R.style.NavigationMapRoute);
                    }
                    navigationMapRoute.addRoute(currentRoute);
                }

                @Override
                public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
                    Log.e(TAG, "Error: " + throwable.getMessage());
                }
            });
    }

    @SuppressWarnings( {"MissingPermission"})
    private void enableLocationComponent(@NonNull Style loadedMapStyle) {
        // Check if permissions are enabled and if not request
        if (PermissionsManager.areLocationPermissionsGranted(this)) {
            // Activate the MapboxMap LocationComponent to show user location
            // Adding in LocationComponentOptions is also an optional parameter
            locationComponent = mapboxMap.getLocationComponent();
            locationComponent.activateLocationComponent(this, loadedMapStyle);
            locationComponent.setLocationComponentEnabled(true);
            // Set the component's camera mode
            locationComponent.setCameraMode(CameraMode.TRACKING);
        } 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) {
            enableLocationComponent(mapboxMap.getStyle());
        } else {
            Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();
            finish();
        }
    }

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

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

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

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

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

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

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

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.mapbox.mapboxsdk.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        mapbox:mapbox_cameraTargetLat="38.9098"
        mapbox:mapbox_cameraTargetLng="-77.0295"
        mapbox:mapbox_cameraZoom="12" />

    <Button
        android:id="@+id/startButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:background="@color/mapboxGrayLight"
        android:enabled="false"
        android:text="Start navigation"
        android:textColor="@color/mapboxWhite"
        mapbox:layout_constraintStart_toStartOf="parent"
        mapbox:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="NavigationMapRoute">
        <!-- Colors -->
        <item name="routeColor">@color/mapboxBlue</item>
        <item name="routeModerateCongestionColor">@color/mapboxYellow</item>
        <item name="routeSevereCongestionColor">@color/mapboxPink</item>
        <item name="routeShieldColor">@color/mapboxWhite</item>
        <!-- Scales -->
        <item name="routeScale">1.0</item>
    </style>

    <style name="NavigationView" parent="Theme.AppCompat.NoActionBar">
        <item name="navigationViewPrimary">@color/mapboxWhite</item>
        <item name="navigationViewSecondary">@color/mapboxBlue</item>
        <item name="navigationViewAccent">@color/mapboxPink</item>
    </style>

</resources>

All 4 comments

Hey 馃憢 thanks for the feedback here @hmkum. This looks to be occurring when instantiating the annotation plugin - @tobrun @LukasPaczos have you seen something like this?

Looks like a lambda failure, does your project support Java 8 @hmkum?

If not, please add below to your build.gradle and let us know if it resolves your issue, thank you!

android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
  ...
}

Adding Java 8 support fixed the issue, now navigation works. Thank you!

Awesome news @hmkum Thanks for the update!

Closing as resolved.

Was this page helpful?
0 / 5 - 0 ratings