嗨,我使用mapbox(Java)在android studio上,想让我的用户位置和导航工作,但我有错误,当我运行开始导航按钮,然后崩溃,请你能帮助我,我已经卡了4天了。
我的MapActivity.java
package com.example.a18004671_opsc7312_taskapp;
import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.os.PersistableBundle;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
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.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
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.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.services.android.navigation.ui.v5.NavigationLauncher;
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 org.jetbrains.annotations.NotNull;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
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;
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback,
MapboxMap.OnMapClickListener, PermissionsListener {
MapView mapView;
MapboxMap mapboxMap;
LocationComponent locationComponent;
PermissionsManager permissionsManager;
DirectionsRoute currentRoute;
NavigationMapRoute navigationMapRoute;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this, "pk.eyJ1IjoiY29zdGFuZGlubyIsImEiOiJja2F4c2E0aDAwNnp6MndwaWtvY3RnMXRmIn0.blAhMKMqI8ejvU-clCPYdQ");
setContentView(R.layout.activity_map);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
public void startNavigationBtnClick(View v) {
boolean simulateRoute = true;
NavigationLauncherOptions options = NavigationLauncherOptions.builder()
.directionsRoute(currentRoute)
.shouldSimulateRoute(simulateRoute)
.build();
NavigationLauncher.startNavigation(MapActivity.this, options);
}
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
enableLocationComponent(mapboxMap.getStyle());
} else {
Toast.makeText(getApplicationContext(), "Permission not granted", Toast.LENGTH_LONG).show();
finish();
}
}
@Override
public boolean onMapClick(@NonNull LatLng point) {
Point destinationPoint = Point.fromLngLat(point.getLongitude(), point.getLatitude());
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
}
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);
return true;
}
private void getRoute(Point originPoint, Point destinationPoint)
{
NavigationRoute.builder(this)
.accessToken(Mapbox.getAccessToken())
.origin(originPoint)
.destination(destinationPoint)
.build()
.getRoute(new Callback<DirectionsResponse>() {
@Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
if(response.body()!=null && response.body().routes().size()>1)
{
currentRoute = response.body().routes().get(0);
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 t) {
}
});
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
this.mapboxMap.setMinZoomPreference(12);
mapboxMap.setStyle(getString(R.string.navigation_guidance_day), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
enableLocationComponent(style);
addDestinationIconLayer(style);
mapboxMap.addOnMapClickListener(MapActivity.this);
}
});
}
private void addDestinationIconLayer(Style style)
{
style.addImage("destination-icon-id",
BitmapFactory.decodeResource(this.getResources(),R.drawable.mapbox_marker_icon_default));
GeoJsonSource geoJsonSource = new GeoJsonSource("destination-source-id");
style.addSource(geoJsonSource);
SymbolLayer destinationSymbolLayer = new SymbolLayer("destination-symbol-layer-id","destination-source-id");
destinationSymbolLayer.withProperties(iconImage("destination-icon-id"),iconAllowOverlap(true),
iconIgnorePlacement(true));
style.addLayer(destinationSymbolLayer);
}
private void enableLocationComponent(@NotNull Style loadedMapStyle) {
if (PermissionsManager.areLocationPermissionsGranted(this)) {
locationComponent = mapboxMap.getLocationComponent();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationComponent.activateLocationComponent(this, loadedMapStyle);
locationComponent.setLocationComponentEnabled(true);
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
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
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
我的XML布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.a18004671_opsc7312_taskapp.MapActivity">
<com.mapbox.mapboxsdk.maps.MapView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/mapView"
android:layout_below="@+id/button"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Navigation"
android:id="@+id/button"
android:onClick="startNavigationBtnClick"
/>
</RelativeLayout>
和错误,我得到
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.a18004671_opsc7312_taskapp, PID: 414
java.lang.IllegalStateException: Could not execute method for android:onClick
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:402)
at android.view.View.performClick(View.java:7357)
at android.view.View.performClickInternal(View.java:7334)
at android.view.View.access$3600(View.java:808)
at android.view.View$PerformClick.run(View.java:28200)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7478)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:397)
at android.view.View.performClick(View.java:7357)
at android.view.View.performClickInternal(View.java:7334)
at android.view.View.access$3600(View.java:808)
at android.view.View$PerformClick.run(View.java:28200)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7478)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
Caused by: java.lang.NullPointerException: Null directionsRoute
at com.mapbox.services.android.navigation.ui.v5.AutoValue_NavigationLauncherOptions$Builder.directionsRoute(AutoValue_NavigationLauncherOptions.java:168)
at com.example.a18004671_opsc7312_taskapp.MapActivity.startNavigationBtnClick(MapActivity.java:75)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:397)
at android.view.View.performClick(View.java:7357)
at android.view.View.performClickInternal(View.java:7334)
at android.view.View.access$3600(View.java:808)
at android.view.View$PerformClick.run(View.java:28200)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7478)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
错误信息提示可能是 currentRoute
当点击按钮时,还没有设置。
这就是为什么 directionsRoute(currentRoute)
抛出 NullPointerException
.
为了解决这个问题,你可以检查是否 currentRoute
中使用前已设定好。startNavigationBtnClick
.
它的实现可以是这样的。
public void startNavigationBtnClick(View v) {
if (currentRoute == null) {
return; // Route has not been set, so we ignore the button press
}
boolean simulateRoute = true;
NavigationLauncherOptions options = NavigationLauncherOptions.builder()
.directionsRoute(currentRoute)
.shouldSimulateRoute(simulateRoute)
.build();
NavigationLauncher.startNavigation(MapActivity.this, options);
}