React Native version is 59.5
We use https://github.com/SRHealth/react-native-mapbox-navigation but this example renders mapboxnavigationview different view. We don't want to works like that.
We are using Mapbox Navigation on our application. iOS works fine but Android has ANR Problem.
Mapbox iOS has not any problem. It works like a charm.
Android is freezing but not all times.
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):
My native component which is 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) {
}
}
}
I did not find any solution.