Track current location on NavNextbillionMap

This example shows how to request and update user location on NavNextbillionMap.

  • Activity will get and display the user's location on a map once the map is loaded successfully

  • A floating button is provided on the screen, each time user clicks on the button, the camera will focus and zoom to the user's current location

In this example we do not handle location permission requests, you can refer to the official guide for assistance: https://developer.android.com/training/location/permissions

docs-image

For all code examples, refer to Navigation Code Examples

activity_track_current_location.xml view source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.TrackCurrentLocationActivity">

    <ai.nextbillion.maps.core.MapView
        android:id="@+id/mapView_get_location"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:nbmap_uiAttribution="false" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/get_location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="16dp"
        app:srcCompat="@drawable/ic_get_location" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

TrackCurrentLocationActivity view source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package ai.nextbillion.navigation.demo.activity;

import android.location.Location;
import android.os.Bundle;

import ai.nextbillion.maps.Nextbillion;
import ai.nextbillion.maps.camera.CameraUpdate;
import ai.nextbillion.maps.camera.CameraUpdateFactory;
import ai.nextbillion.maps.core.MapView;
import ai.nextbillion.maps.core.NextbillionMap;
import ai.nextbillion.maps.core.OnMapReadyCallback;
import ai.nextbillion.maps.core.Style;
import ai.nextbillion.maps.geometry.LatLng;
import ai.nextbillion.maps.location.engine.LocationEngine;
import ai.nextbillion.maps.location.engine.LocationEngineCallback;
import ai.nextbillion.maps.location.engine.LocationEngineProvider;
import ai.nextbillion.maps.location.engine.LocationEngineRequest;
import ai.nextbillion.maps.location.engine.LocationEngineResult;
import ai.nextbillion.maps.location.modes.RenderMode;
import ai.nextbillion.navigation.demo.R;
import ai.nextbillion.navigation.ui.camera.CameraUpdateMode;
import ai.nextbillion.navigation.ui.camera.NavigationCameraUpdate;
import ai.nextbillion.navigation.ui.map.NavNextbillionMap;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.lang.ref.WeakReference;

/***
 * The example shows how to request user location and display on our MapView
 * it assumes that you have granted location permissions for your application.
 * if location permission is not granted, the demo code will not be able to fetch device location properly
 */

public class TrackCurrentLocationActivity extends AppCompatActivity implements OnMapReadyCallback {
    private static final int CAMERA_ANIMATION_DURATION = 1000;
    private static final int DEFAULT_CAMERA_ZOOM = 16;
    private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
    private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500;

    private MapView mapView;
    private FloatingActionButton floatingActionButton;
    private NavNextbillionMap nbMap;
    private final TrackCurrentLocationCallback callback = new TrackCurrentLocationCallback(this);
    private LocationEngine locationEngine;
    private Location lastLocation;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_track_current_location);
        mapView = findViewById(R.id.mapView_get_location);
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(this);

        setUpFloatingButton();
    }

    private void setUpFloatingButton() {
        floatingActionButton = findViewById(R.id.get_location);
        floatingActionButton.setOnClickListener(v -> animateCamera());
    }

    // This function demonstrate how to focus camera to user location with certain zoom level
    private void animateCamera() {
        if (lastLocation != null) {
            CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()), DEFAULT_CAMERA_ZOOM);
            NavigationCameraUpdate navigationCameraUpdate = new NavigationCameraUpdate(cameraUpdate);
            navigationCameraUpdate.setMode(CameraUpdateMode.OVERRIDE);
            nbMap.retrieveCamera().update(navigationCameraUpdate, CAMERA_ANIMATION_DURATION);
        }
    }

    @Override
    public void onMapReady(@NonNull NextbillionMap nextbillionMap) {
        nextbillionMap.setStyle(new Style.Builder().fromUri("https://api.nextbillion.io/maps/streets/style.json"));
        nextbillionMap.getStyle(style -> {
            nbMap = new NavNextbillionMap(mapView, nextbillionMap);
            nbMap.updateLocationLayerRenderMode(RenderMode.GPS);
            initializeLocationEngine();
        });
    }

    private void onLocationFound(Location location) {
        lastLocation = location;
        nbMap.updateLocation(location);
    }

    private LocationEngineRequest buildEngineRequest() {
        return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS)
                .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
                .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS)
                .build();
    }

    @SuppressWarnings({"MissingPermission"})
    private void initializeLocationEngine() {
        // here we use location engine to update user current location
        locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext());
        LocationEngineRequest request = buildEngineRequest();
        locationEngine.requestLocationUpdates(request, callback, null);
        locationEngine.getLastLocation(callback);
    }

    private static class TrackCurrentLocationCallback implements LocationEngineCallback<LocationEngineResult> {

        private final WeakReference<TableRowackCurrentLocationActivity> activityWeakReference;

        TrackCurrentLocationCallback(TrackCurrentLocationActivity activity) {
            this.activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void onSuccess(LocationEngineResult locationEngineResult) {
            TrackCurrentLocationActivity activity = activityWeakReference.get();
            if (activity != null) {
                Location location = locationEngineResult.getLastLocation();
                if (location == null) {
                    return;
                }
                activity.onLocationFound(location);
            }
        }

        @Override
        public void onFailure(@NonNull Exception e) {

        }
    }


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

    @SuppressWarnings({"MissingPermission"})
    @Override
    public void onResume() {
        super.onResume();
        mapView.onResume();
        if (locationEngine != null) {
            locationEngine.requestLocationUpdates(buildEngineRequest(), callback, null);
        }
    }

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

    @Override
    public void onPause() {
        super.onPause();
        mapView.onPause();
        if (locationEngine != null) {
            locationEngine.removeLocationUpdates(callback);
        }
    }

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }
}

Code Highlights

  • The mapView.getMapAsync() function will trigger the onMapReady() override function, and we set the map style and mode here.

  • The location engine initialization is also done in the onMapReady() function, it will try to get the device's last known location, then use nbMap.updateLocation() to show the location info on map

  • The code example also uses a float button to adjust the camera position and zoom level to provide a better visual experience to the user.

Code summary

The code snippet is for an Android activity that tracks the current location of the user and displays it on a map. The activity first creates a MapView object and sets its onCreate() listener. The onCreate() listener then gets the map's getStyle() and uses it to create a NavNextbillionMap object. The NavNextbillionMap object is then used to update the map's location layer render mode to RenderMode.GPS.

The activity then creates a LocationEngine object and requests location updates from it. The location updates are received by the TrackCurrentLocationCallback object, which updates the map's location with the latest location information.

The activity also has a FloatingActionButton object that is used to focus the camera on the user's current location. When the FloatingActionButton is clicked, the activity calls the animateCamera() method, which focuses the camera on the user's current location.

The activity implements the following lifecycle methods:

onStart(): This method is called when the activity starts. It calls the onStart() method of the MapView object.

onResume(): This method is called when the activity resumes. It calls the onResume() method of the MapView object and requests location updates from the LocationEngine object.

onLowMemory(): This method is called when the device is low on memory. It calls the onLowMemory() method of the MapView object.

onPause(): This method is called when the activity pauses. It calls the onPause() method of the MapView object and removes location updates from the LocationEngine object.

onStop(): This method is called when the activity stops. It calls the onStop() method of the MapView object.

onDestroy(): This method is called when the activity is destroyed. It calls the onDestroy() method of the MapView object.

The activity also uses the following constants:

CAMERA_ANIMATION_DURATION: This constant is the duration of the animation used to focus the camera on the user's current location.

DEFAULT_CAMERA_ZOOM: This constant is the default zoom level of the map.

UPDATE_INTERVAL_IN_MILLISECONDS: This constant is the interval at which the LocationEngine object requests location updates.

FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS: This constant is the minimum interval at which the LocationEngine object requests location updates.

The activity uses the following classes:

  • MapView: This class represents a map view.

  • FloatingActionButton: This class represents a floating action button.

  • NextbillionMap: This class represents a Nextbillion map.

  • LocationEngine: This class provides access to location services.

  • LocationEngineRequest: This class represents a request for location updates.

  • LocationEngineResult: This class represents the result of a location update request.

  • TrackCurrentLocationCallback: This class implements the LocationEngineCallback interface and is used to receive location updates.

Have Questions ?