React Native версия: 59.5
Мы используем https://github.com/SRHealth/react-native-mapbox-navigation, но в этом примере отображается mapboxnavigationview. Мы не хотим так работать.
Мы используем Mapbox Navigation в нашем приложении. iOS работает нормально, но у Android есть проблема ANR.
Mapbox iOS не имеет никаких проблем. Это работает как шарм.
Android зависает, но не всегда.
Logcat;
10-23 12:03:40.907 2104 2239 E ActivityManager: ANR in com.mybundle (com.mybunle/.MainActivity)
10-23 12:03:40.907 2104 2239 E ActivityManager: PID: 25847
10-23 12:03:40.907 2104 2239 E ActivityManager: Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 2. Wait queue head age: 48808.3ms.)
10-23 12:03:40.907 2104 2239 E ActivityManager: Load: 9.4 / 9.37 / 8.86
10-23 12:03:40.907 2104 2239 E ActivityManager: CPU usage from 0ms to 8134ms later (2019-10-23 12:03:32.741 to 2019-10-23 12:03:40.876):
Мой родной компонент, который является mapboxnavigationview;
package com.mybundle.Mapbox;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.location.Location;
// import android.support.annotation.NonNull;
// import android.support.annotation.Nullable;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import android.view.View;
import android.widget.LinearLayout;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.mapbox.android.core.location.LocationEngine;
import com.mapbox.android.core.location.LocationEngineCallback;
import com.mapbox.android.core.location.LocationEngineProvider;
import com.mapbox.android.core.location.LocationEngineRequest;
import com.mapbox.android.core.location.LocationEngineResult;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
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.services.android.navigation.ui.v5.camera.DynamicCamera;
import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCamera;
import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCameraUpdate;
import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionView;
import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap;
import com.mapbox.services.android.navigation.ui.v5.voice.NavigationSpeechPlayer;
import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.ui.v5.voice.SpeechPlayerProvider;
import com.mapbox.services.android.navigation.ui.v5.voice.VoiceInstructionLoader;
import com.mapbox.services.android.navigation.v5.milestone.Milestone;
import com.mapbox.services.android.navigation.v5.milestone.MilestoneEventListener;
import com.mapbox.services.android.navigation.v5.milestone.VoiceInstructionMilestone;
import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.offroute.OffRouteListener;
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
import com.mybundle.R;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Locale;
import okhttp3.Cache;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import timber.log.Timber;
public class MapboxNavigationView extends LinearLayout implements OnMapReadyCallback,
MapboxMap.OnMapLongClickListener, ProgressChangeListener, MilestoneEventListener, OffRouteListener {
private static final int FIRST = 0;
private static final int ONE_HUNDRED_MILLISECONDS = 100;
private static final int BOTTOMSHEET_PADDING_MULTIPLIER = 4;
private static final int TWO_SECONDS_IN_MILLISECONDS = 2000;
private static final double BEARING_TOLERANCE = 90d;
private static final String LONG_PRESS_MAP_MESSAGE = "Long press the map to select a destination.";
private static final String SEARCHING_FOR_GPS_MESSAGE = "Searching for GPS...";
private static final String COMPONENT_NAVIGATION_INSTRUCTION_CACHE = "component-navigation-instruction-cache";
private static final long TEN_MEGABYTE_CACHE_SIZE = 10 * 1024 * 1024;
private static final int ZERO_PADDING = 0;
private static final double DEFAULT_ZOOM = 12.0;
private static final double DEFAULT_TILT = 0d;
private static final double DEFAULT_BEARING = 0d;
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500;
private Context context;
private final MapboxNavigationViewLocationCallback callback = new MapboxNavigationViewLocationCallback(this);
private LocationEngine locationEngine;
private MapboxNavigation navigation;
private NavigationSpeechPlayer speechPlayer;
private NavigationMapboxMap navigationMap;
private Location lastLocation;
private DirectionsRoute route;
private Point destination = null;
private InstructionView instructionView;
private MapView mapView;
private boolean mapLoaded = false;
public MapboxNavigationView(ReactApplicationContext reactContext) {
super(reactContext);
this.context = reactContext;
context.setTheme(R.style.CustomInstructionView);
inflate(context, R.layout.navigation_view, this);
mapView = findViewById(R.id.mapView);
instructionView = findViewById(R.id.instructionView);
mapView.onCreate(null);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mapboxMap.setStyle(new Style.Builder().fromUri(context.getString(R.string.navigation_guidance_day)), style -> {
navigationMap = new NavigationMapboxMap(mapView, mapboxMap);
// For Location updates
initializeLocationEngine();
// For navigation logic / processing
initializeNavigation(mapboxMap);
navigationMap.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE);
navigationMap.updateLocationLayerRenderMode(RenderMode.GPS);
// For voice instructions
initializeSpeechPlayer();
mapLoaded = true;
if(destination != null)
{
navigateToDestination(destination);
}
});
}
@Override
public boolean onMapLongClick(@NonNull LatLng point) {
// Only reverse geocode while we are not in navigation
return false;
}
/*
* Navigation listeners
*/
@Override
protected void onDetachedFromWindow() {
navigation.onDestroy();
super.onDetachedFromWindow();
}
@Override
public void onProgressChange(Location location, RouteProgress routeProgress) {
// Cache "snapped" Locations for re-route Directions API requests
updateLocation(location);
// Update InstructionView data from RouteProgress
instructionView.updateDistanceWith(routeProgress);
}
@Override
public void onMilestoneEvent(RouteProgress routeProgress, String instruction, Milestone milestone) {
playAnnouncement(milestone);
// Update InstructionView banner instructions
instructionView.updateBannerInstructionsWith(milestone);
}
@Override
public void userOffRoute(Location location) {
calculateRouteWith(destination, true);
}
/*
* Activity lifecycle methods
*/
void checkFirstUpdate(Location location) {
if (lastLocation == null) {
lastLocation = location;
moveCameraTo(location);
if(destination != null ) navigateToDestination(destination);
// Allow navigationMap clicks now that we have the current Location
}
}
void updateLocation(Location location) {
lastLocation = location;
navigationMap.updateLocation(location);
}
private void initializeSpeechPlayer() {
String english = "en";
String lng = Locale.getDefault().getDisplayLanguage();
if(lng.equals("Deutsch")){
english = "de";
}
Cache cache = new Cache(new File(context.getCacheDir(), COMPONENT_NAVIGATION_INSTRUCTION_CACHE),
TEN_MEGABYTE_CACHE_SIZE);
VoiceInstructionLoader voiceInstructionLoader = new VoiceInstructionLoader(context,
Mapbox.getAccessToken(), cache);
SpeechPlayerProvider speechPlayerProvider = new SpeechPlayerProvider(context, english, true,
voiceInstructionLoader);
speechPlayer = new NavigationSpeechPlayer(speechPlayerProvider);
}
@SuppressLint("MissingPermission")
private void initializeLocationEngine() {
locationEngine = LocationEngineProvider.getBestLocationEngine(context);
LocationEngineRequest request = buildEngineRequest();
locationEngine.requestLocationUpdates(request, callback, null);
}
private void initializeNavigation(MapboxMap mapboxMap) {
navigation = new MapboxNavigation(context, Mapbox.getAccessToken());
navigation.setLocationEngine(locationEngine);
navigation.setCameraEngine(new DynamicCamera(mapboxMap));
navigation.addProgressChangeListener(this);
navigation.addMilestoneEventListener(this);
navigation.addOffRouteListener(this);
navigationMap.addProgressChangeListener(navigation);
}
private void playAnnouncement(Milestone milestone) {
if (milestone instanceof VoiceInstructionMilestone) {
SpeechAnnouncement announcement = SpeechAnnouncement.builder()
.voiceInstructionMilestone((VoiceInstructionMilestone) milestone)
.build();
speechPlayer.play(announcement);
}
}
private void moveCameraTo(Location location) {
CameraPosition cameraPosition = buildCameraPositionFrom(location, location.getBearing());
navigationMap.retrieveMap().animateCamera(
CameraUpdateFactory.newCameraPosition(cameraPosition), TWO_SECONDS_IN_MILLISECONDS
);
}
private void moveCameraToInclude(Point destination) {
LatLng origin = new LatLng(lastLocation);
LatLngBounds bounds = new LatLngBounds.Builder()
.include(origin)
.include(new LatLng(destination.latitude(), destination.longitude()))
.build();
Resources resources = getResources();
int routeCameraPadding = (int) resources.getDimension(R.dimen.component_navigation_route_camera_padding);
int[] padding = {routeCameraPadding, routeCameraPadding, routeCameraPadding, routeCameraPadding};
CameraPosition cameraPosition = navigationMap.retrieveMap().getCameraForLatLngBounds(bounds, padding);
navigationMap.retrieveMap().animateCamera(
CameraUpdateFactory.newCameraPosition(cameraPosition), TWO_SECONDS_IN_MILLISECONDS
);
}
private void moveCameraOverhead() {
if (lastLocation == null) {
return;
}
CameraPosition cameraPosition = buildCameraPositionFrom(lastLocation, DEFAULT_BEARING);
navigationMap.retrieveMap().animateCamera(
CameraUpdateFactory.newCameraPosition(cameraPosition), TWO_SECONDS_IN_MILLISECONDS
);
}
@Nullable
private CameraUpdate cameraOverheadUpdate() {
if (lastLocation == null) {
return null;
}
CameraPosition cameraPosition = buildCameraPositionFrom(lastLocation, DEFAULT_BEARING);
return CameraUpdateFactory.newCameraPosition(cameraPosition);
}
@NonNull
private CameraPosition buildCameraPositionFrom(Location location, double bearing) {
return new CameraPosition.Builder()
.zoom(DEFAULT_ZOOM)
.target(new LatLng(location.getLatitude(), location.getLongitude()))
.bearing(bearing)
.tilt(DEFAULT_TILT)
.build();
}
private void adjustMapPaddingForNavigation() {
Resources resources = getResources();
int mapViewHeight = mapView.getHeight();
int bottomSheetHeight = (int) resources.getDimension(R.dimen.component_navigation_bottomsheet_height);
int topPadding = mapViewHeight - (bottomSheetHeight * BOTTOMSHEET_PADDING_MULTIPLIER);
navigationMap.retrieveMap().setPadding(ZERO_PADDING, topPadding, ZERO_PADDING, ZERO_PADDING);
}
private void resetMapAfterNavigation() {
navigationMap.removeRoute();
navigationMap.clearMarkers();
navigation.stopNavigation();
moveCameraOverhead();
}
private void removeLocationEngineListener() {
if (locationEngine != null) {
locationEngine.removeLocationUpdates(callback);
}
}
@SuppressLint("MissingPermission")
private void addLocationEngineListener() {
if (locationEngine != null) {
LocationEngineRequest request = buildEngineRequest();
locationEngine.requestLocationUpdates(request, callback, null);
}
}
private void calculateRouteWith(Point destination, boolean isOffRoute) {
Point origin = Point.fromLngLat(lastLocation.getLongitude(), lastLocation.getLatitude());
Double bearing = Float.valueOf(lastLocation.getBearing()).doubleValue();
NavigationRoute.builder(context)
.accessToken(Mapbox.getAccessToken())
.origin(origin, bearing, BEARING_TOLERANCE)
.destination(destination)
.build()
.getRoute(new Callback<DirectionsResponse>() {
@Override
public void onResponse(@NonNull Call<DirectionsResponse> call, @NonNull Response<DirectionsResponse> response) {
handleRoute(response, isOffRoute);
}
@Override
public void onFailure(@NonNull Call<DirectionsResponse> call, @NonNull Throwable throwable) {
Timber.e("fuck;");
}
});
}
public void navigateToDestination(Point destination)
{
this.destination = destination;
if(mapLoaded && lastLocation != null) calculateRouteWith(destination, false);
}
private void quickStartNavigation() {
// Transition to navigation state
// Show the InstructionView
instructionView.setVisibility(View.VISIBLE);
adjustMapPaddingForNavigation();
// Updates camera with last location before starting navigating,
// making sure the route information is updated
// by the time the initial camera tracking animation is fired off
// Alternatively, NavigationMapboxMap#startCamera could be used here,
// centering the map camera to the beginning of the provided route
navigationMap.resumeCamera(lastLocation);
navigation.startNavigation(route);
// Location updates will be received from ProgressChangeListener
removeLocationEngineListener();
// TODO remove example usage
navigationMap.resetCameraPositionWith(NavigationCamera.NAVIGATION_TRACKING_MODE_GPS);
CameraUpdate cameraUpdate = cameraOverheadUpdate();
if (cameraUpdate != null) {
NavigationCameraUpdate navUpdate = new NavigationCameraUpdate(cameraUpdate);
navigationMap.retrieveCamera().update(navUpdate);
}
}
private void handleRoute(Response<DirectionsResponse> response, boolean isOffRoute) {
List<DirectionsRoute> routes = response.body().routes();
if (!routes.isEmpty()) {
route = routes.get(FIRST);
navigationMap.drawRoute(route);
if (isOffRoute) {
navigation.startNavigation(route);
}else quickStartNavigation();
}
}
@NonNull
private LocationEngineRequest buildEngineRequest() {
return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS)
.build();
}
private static class MapboxNavigationViewLocationCallback implements LocationEngineCallback<LocationEngineResult> {
private final WeakReference<MapboxNavigationView> activityWeakReference;
MapboxNavigationViewLocationCallback(MapboxNavigationView activity) {
this.activityWeakReference = new WeakReference<>(activity);
}
@Override
public void onSuccess(LocationEngineResult result) {
MapboxNavigationView activity = activityWeakReference.get();
if (activity != null) {
Location location = result.getLastLocation();
if (location == null) {
return;
}
activity.checkFirstUpdate(location);
activity.updateLocation(location);
}
}
@Override
public void onFailure(@NonNull Exception exception) {
}
}
}
Я не нашел никакого решения.