Using Mapbox Maps SDK for Android - Java

 I’m going to study implementing Map-related application. I have searched several map service provider and finally decide to try Mapbox.

Why Mapbox?

There are several map service providers. Google Map is the most popular one, which is the default map application in Android phones. HereMap and TomTom also are famous. If the app only requires showing the map and the point of interest in the map, we can use their Map SDK. However, the Navigation SDK is restricted at this moment. It needs to send an official request to discuss with them in order to access the navigation SDK.     

Although Mapbox is young and less famous, it is open to register an account and apply for Token. Key to access Map SDK and Navigation SDK. As long as your usage of the service does not exceed the limited amount, it is free to use. Therefore, I choose Mapbox for self-learning.


First, go to Mapbox website to sign up for an account. Then go to the document page to select which part to study.

I will studied in those 4 aspects

  1. Show the device location on the map (Maps SDK)

  2. Search the location of place by typing the name (Search SDK)

  3. Request routes and draw on the map (Navigation SDK)

  4. Navigation (Navigation SDK)


Only Koltin source code is provided in the document page. I will follow some of the tutorials and examples in the document page and implement the examples in Java. It may help someone who have not studied Koltin yet.

Create Token keys and keep them Securely

Following the instructions in the document page, we need to have 1 public token key(to use the instance of key components in SDK) and a secret token key with Downloads:read scop (to download the SDK from Mapbox server to Android Studio).


Mapbox bills us according to the usage of service of each token key. Therefore, it is important to keep the token key hidden to public

We configure Git to not track the file which stores the keys.

  1. Create or open .gitignore file. Add a file name with relative path in the file: for example, YOUR_APP_MODULE_NAME/src/main/res/values/non-disclosure.xml

  2. Create the xml file with the same name and location that you add in step 1. Then Git will not trace and upload this file.

  3. Add your public token in this xml file <string name="mapbox_access_token">PASTE_YOUR_TOKEN_HERE</string>

  4. Similarly, add the secret token in file gradle.properties and make Git not to trace and upload this file.

MAPBOX_DOWNLOADS_TOKEN=YOUR_SECRET_MAPBOX_ACCESS_TOKEN

Check Dependencies of each SDK

If you want to use Maps SDK, Search SDK and Navigation in the same project, please check the dependencies of each SDK. Make sure the version of dependencies required by each SDK are the same.

Add the corresponding SDK in module build.gradle and settings.gradle by following the official instructions.

Add MapView

First add MapView in the layout xml file(I put it into Fragment layout for example). We can set the default location that the camera looks at when the fragment is created each time with the parameter “mapbox:mapbox_cameraTargetLat” and “mapbox:mapbox_cameraTargetLng”.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".ShowMapFragment">

   <com.mapbox.maps.MapView
       xmlns:mapbox="http://schemas.android.com/apk/res-auto"
       android:id="@+id/mapView"
       mapbox:layout_constraintBottom_toBottomOf="parent"
       mapbox:layout_constraintEnd_toEndOf="parent"
       mapbox:layout_constraintStart_toStartOf="parent"
       mapbox:layout_constraintTop_toTopOf="parent"
       mapbox:mapbox_cameraTargetLat="40.7128"
       mapbox:mapbox_cameraTargetLng="-74.0060"
       mapbox:mapbox_cameraZoom="16.0"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Then we get the instance from method onViewCreated() and set the map style
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
   super.onViewCreated(view, savedInstanceState);
   mapView = binding.mapView;

   mapView.getMapboxMap().loadStyleUri(Style.MAPBOX_STREETS, new Style.OnStyleLoaded(){
       @Override
       public void onStyleLoaded(Style style){

       }
   });
}

We override the lifecycle method and invoke the corresponding MapView method so that the MapView can maintain the same lifecycle state as the Fragment.
@Override
public void onStart(){
   super.onStart();
   mapView.onStart();
}

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

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

@Override
public void onDestroyView() {
   super.onDestroyView();
   mapView.onDestroy();
   binding = null;
}

Now the Map can be shown on the screen. Next step we will go to show our location on the map and make the camera(phone screen) focus on it.

Show Device Location

In order to show the device Location, app must grant ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permission.

Mapbox has implemented a Location Provider object to deal with the device location by utilising Android GPS and Network Location Providers and Google fused Location Providers . All we need is to enable the MapView to show the device location after the location permissions granted and device’s GPS turn on.

We look at the example Display the user's location which is programmed in Koltin. This part is to enable the MapView to display the device location.

private fun initLocationComponent() {
    val locationComponentPlugin = mapView.location
    locationComponentPlugin.updateSettings {
        this.enabled = true
        this.locationPuck = LocationPuck2D( bearingImage = AppCompatResources.getDrawable(
        this@LocationTrackingActivity, R.drawable.mapbox_user_puck_icon,),
    .
}

In Java, we need to use one of these 2 methods to get LocationCompoentPlugin Class which controls the location display and the icon representing the device location.

LocationComponentPlugin2 locationComponentPlugin = mapView.getPlugin(Plugin.MAPBOX_LOCATION_COMPONENT_PLUGIN_ID);
LocationComponentPlugin2 locationComponentPlugin = LocationComponentUtils.getLocationComponent2(mapView); 7

We set enable to allow device location display on the map. By default, it is represented by a blue circle with white perimeter.
LocationComponentPlugin2 locationComponentPlugin = mapView.getPlugin(Plugin.MAPBOX_LOCATION_COMPONENT_PLUGIN_ID);
locationComponentPlugin.setEnabled(true);

If we want the direction of the device to be shown on the map also, we create a 2D puck with bearing and then set the 2D puck into the LocationComponentPlugin2 object. I use Default2DPuck here for simplicity but we can also create a customised 2DPuck or 3D Puck by providing the images.

LocationPuck2D puck2D = LocationComponentUtils.createDefault2DPuck(locationComponentPlugin, getContext(), true);
locationComponentPlugin.setLocationPuck(puck2D);
locationComponentPlugin.setPuckBearingEnabled(true); // enable the puck to rotate to track the device bearing
locationComponentPlugin.setPuckBearingSource(PuckBearingSource.HEADING);

Change Camera viewing position at the device location

Now we move the device and so as the blue spot on the screen. If we want the blue spot to always stay at the centre of the screen even if we move around. We can set the camera in the  OnIndicatorPositionChangedListener, in which method will be invoked every time the device location changes. We also set the focal point of gesture here so that the camera will rotate and zoom at the device position.

private OnIndicatorPositionChangedListener onIndicatorPositionChangedListener = new OnIndicatorPositionChangedListener(){
   @Override
   public void onIndicatorPositionChanged(Point point){
       mapView.getMapboxMap().setCamera(new           CameraOptions.Builder().center(point).build());
       GesturesPlugin gesturesPlugin = mapView.getPlugin(Plugin.MAPBOX_GESTURES_PLUGIN_ID);
       gesturesPlugin.setFocalPoint(mapView.getMapboxMap().pixelForCoordinate(point));
   }
};

If we hope the map automatically rotates as the device so that the bearing direction of the blue spot always points to the top side of the screen. We could use OnIndicatorBearingChangedListener. We set the pointing direction of the camera when the bearing of the device changes.

private final OnIndicatorBearingChangedListener onIndicatorBearingChangedListener = new OnIndicatorBearingChangedListener(){
   @Override
   public void onIndicatorBearingChanged(double bearing){
       mapView.getMapboxMap().setCamera(new CameraOptions.Builder().bearing(bearing).build());
   }
};

If we want to look at other places on the map, we swipe the screen. At this moment, we may not want the camera to automatically recenter at the device location. Therefore, we need to remove the above changed listeners when we move the map.


private final OnMoveListener onMoveListener = new OnMoveListener() {
   @Override
   public void onMoveBegin(@NotNull MoveGestureDetector moveGestureDetector) {
       onCameraTrackingDismissed();
   }

   @Override
   public boolean onMove(@NotNull MoveGestureDetector moveGestureDetector) {
       return false;
   }

   @Override
   public void onMoveEnd(@NotNull MoveGestureDetector moveGestureDetector) {

   }
};

OnMoveListener is the interface responsible for gesture events. We add this listener into GesturePlugin and invoke the method onCameraTackingDismissed() to remove the relevant listener when a user gesture is detected.

GesturesPlugin gesturesPlugin = mapView.getPlugin(Plugin.MAPBOX_GESTURES_PLUGIN_ID);
gesturesPlugin.addOnMoveListener(onMoveListener);

This is the end of the study on the example Display the user's location. Next time, I will study the Mapbox Search SDK for Geocoding (get the coordinate of a place by providing the name of the place) .

View the source code in GitHub.

留言

此網誌的熱門文章

Use okhttp to download file and show progress bar

Download File into app specific storage with Retrofit

Unzipp file with Zip4j library