Mapbox NavigationView.startNavigation 崩溃 -- 索引 0;大小 0

Mapbox NavigationView.startNavigation crash -- Index 0;Size 0

标题非常简单明了,我一直在尝试使用 Java 的 Navigation SDK UI 组件开始导航。它会生成路线(我可以保证是 not-null)但是当我尝试开始导航时它似乎崩溃了。它开始于从单独的 activity 中单击按钮,该按钮以 JSON.

传递 2 点

堆栈跟踪:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.b31project.aanproject, PID: 8148
    java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
        at java.util.ArrayList.get(ArrayList.java:437)
        at com.mapbox.navigation.ui.route.MapRouteLine$MapRouteLineSupport.buildWayPointFeatureFromLeg(MapRouteLine.kt:1333)
        at com.mapbox.navigation.ui.route.MapRouteLine$MapRouteLineSupport.buildWayPointFeatureCollection(MapRouteLine.kt:1310)
        at com.mapbox.navigation.ui.route.MapRouteLine.drawWayPoints(MapRouteLine.kt:694)
        at com.mapbox.navigation.ui.route.MapRouteLine.reinitializeWithRoutes(MapRouteLine.kt:466)
        at com.mapbox.navigation.ui.route.MapRouteLine.draw(MapRouteLine.kt:430)
        at com.mapbox.navigation.ui.route.NavigationMapRoute.addRoutes(NavigationMapRoute.java:199)
        at com.mapbox.navigation.ui.route.NavigationMapRoute.addRoute(NavigationMapRoute.java:179)
        at com.mapbox.navigation.ui.map.NavigationMapboxMap.drawRoute(NavigationMapboxMap.java:556)
        at com.mapbox.navigation.ui.NavigationView.startNavigation(NavigationView.java:452)
        at com.b31project.aanproject.Navigation.onResponse(Navigation.java:112)
        at com.mapbox.api.directions.v5.MapboxDirections.onResponse(MapboxDirections.java:186)
        at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=11=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:81)
        at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCallwC8FyV4pyjrzrYL5U0mlYiviZw.run(Unknown Source:6)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

XML:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.mapbox.navigation.ui.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        mapbox:mapbox_cameraZoom="1"
        />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Navigation.java


package com.b31project.aanproject;

import android.content.Intent;
import android.graphics.Path;
import android.location.Location;
import android.os.Bundle;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.mapbox.android.core.location.LocationEngineProvider;
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.RouteOptions;
import com.mapbox.mapboxsdk.Mapbox;

import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.navigation.base.internal.route.RouteUrl;
import com.mapbox.navigation.base.options.NavigationOptions;
import com.mapbox.navigation.core.MapboxNavigation;
import com.mapbox.navigation.core.MapboxNavigationProvider;
import com.mapbox.navigation.ui.NavigationView;
import com.mapbox.navigation.ui.NavigationViewOptions;
import com.mapbox.navigation.ui.OnNavigationReadyCallback;
import com.mapbox.geojson.Point;
import com.mapbox.navigation.ui.listeners.NavigationListener;
import com.mapbox.navigation.ui.map.NavigationMapboxMap;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import timber.log.Timber;


public class Navigation extends AppCompatActivity implements OnNavigationReadyCallback,
        NavigationListener, Callback<DirectionsResponse> {
      private NavigationView navigationView;
      private NavigationMapboxMap navigationMapboxMap;
      private MapboxNavigation navigator;
      private Point origin;
      private Point destination;
      private DirectionsRoute currRoute;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Mapbox.getInstance(this, getString(R.string.mapbox_access_token));
        setContentView(R.layout.activity_navigation);
        setTheme(R.style.Theme_AppCompat_Light_NoActionBar);
        navigationView = findViewById(R.id.navigationView);
        Intent intent = getIntent();
        origin = Point.fromJson(intent.getStringExtra("origin"));
        destination = Point.fromJson(intent.getStringExtra("destination"));
        navigationView.initialize(this);
    }

    @Override
    public void onNavigationReady(boolean isRunning) {
        if(navigationView.retrieveMapboxNavigation() != null){
            navigator = navigationView.retrieveMapboxNavigation();
        }else{
            NavigationOptions n = MapboxNavigation.defaultNavigationOptionsBuilder(this, getString(R.string.mapbox_access_token)).build();
            navigator = new MapboxNavigation(n);
        }
        navigationMapboxMap = navigationView.retrieveNavigationMapboxMap();
        getRoute(origin,destination);
    }

    private void getRoute(Point origin, Point destination){
        MapboxDirections directions = MapboxDirections.builder()
                .accessToken(getString(R.string.mapbox_access_token))
                .origin(origin)
                .destination(destination)
                .overview(DirectionsCriteria.OVERVIEW_FULL)
                .profile(DirectionsCriteria.PROFILE_WALKING)
                .voiceInstructions(true)
                .build();
        directions.enqueueCall(this);
    }


    @Override
    public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
        if(response.body() == null){
            Timber.e("No route found");
            this.onNavigationFinished();
        }else if(response.body().routes().size() < 1){
            Timber.e("Response empty");
            this.onNavigationFinished();
        }else{
            currRoute = response.body().routes().get(0);
        }
        System.out.println(currRoute);
        NavigationViewOptions navigationViewOptions = NavigationViewOptions.builder(this)
                .navigationListener(this)
                .directionsRoute(currRoute)
                .build();
        navigationView.startNavigation(navigationViewOptions);
    }

    @Override
    public void onFailure(Call<DirectionsResponse> call, Throwable t) {
        Timber.e("Error: " + t.getMessage());
        this.onNavigationFinished();
    }

    @Override
    public void onCancelNavigation() {
        navigationView.stopNavigation();
        finish();
    }

    @Override
    public void onNavigationFinished() {
        finish();
    }

    @Override
    public void onNavigationRunning() {

    }
}

应用级别gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    ndkVersion "21.0.6113669"


    defaultConfig {
        applicationId "com.b31project.aanproject"
        minSdkVersion 26
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    compileOptions{
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    repositories{
        mavenCentral()
        maven{url 'https://mapbox.bintray.com/mapbox'}
    }
}

dependencies {
    implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:5.7.0'
    implementation 'com.google.android.gms:play-services-location:17.1.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-places-v9:0.12.0'
    implementation 'com.mapbox.navigation:ui:1.1.0'
}

错误就在 onResponse 的末尾。感谢您的帮助!

您面临的错误似乎源于未将 steps 设置为 true:

请将您的 MapboxDirections.builder() 更改为:

MapboxDirections directions = MapboxDirections.builder()
                .accessToken(getString(R.string.mapbox_access_token))
                .origin(origin)
                .steps(true)
                .destination(destination)
                .overview(DirectionsCriteria.OVERVIEW_FULL)
                .profile(DirectionsCriteria.PROFILE_WALKING)
                .voiceInstructions(true)
                .build();

来自 https://docs.mapbox.com/api/navigation/#retrieve-directions 你需要设置steps = true,否则voiceInstructions不可用。这可能会导致问题。

您的代码的第二个问题:

您需要为语音指令指定一个unitType。因此在 MapboxDirections.builder():

中添加单位类型

 MapboxDirections directions = MapboxDirections.builder()
                .accessToken(getString(R.string.mapbox_access_token))
                .origin(origin)
                .steps(true)
                .destination(destination)
                .overview(DirectionsCriteria.OVERVIEW_FULL)
                .profile(DirectionsCriteria.PROFILE_WALKING)
                .voiceInstructions(true)
                .voiceUnits(VoiceUnit.METRIC)
                .build();

关于缩放:

我建议按照此处的说明在 locationComponent 上设置缩放:https://docs.mapbox.com/android/maps/overview/location-component/#cameramode

第一次实例化 LocationComponent 时,地图的 max/min 缩放级别将分别设置为 toLocationComponentOptions#MAX_ZOOM_DEFAULTLocationComponentOptions#MIN_ZOOM_DEFAULT。用LocationComponentOptionsclass.

中的LocationComponentOptions#maxZoom()LocationComponentOptions#minZoom()方法调整缩放范围