Receiving Android Location Updates
Is your app heavily dependent on geodata, for example if your app is tracking user locations, suggesting best routes to users for say driving jogging, or even if you app just keep track of locations of assets that you late use, it needs to get the location of the device at regular intervals.
You’re able to request periodic updates Android fused location provider. The API updates your app periodically with the best available location, based on the currently-available location providers such as WiFi and GPS (Global Positioning System). The accuracy of the location is determined by the providers, the location permissions you’ve requested, and the options you set in the location request.
In this tutorial, I will shows you how to request regular updates about a device’s location using the requestLocationUpdates() method in the fused location provider.
The fused location provider is one of the location APIs in Google Play services. It manages the underlying location technology and provides a simple API so that you can specify requirements at a high level, like high accuracy or low power. It also optimizes the device’s use of battery power.
Dependencies
1 2 3 4 |
dependencies { compile 'com.google.android.gms:play-services-maps:9.2.0' compile 'com.google.android.gms:play-services-location:9.2.0' } |
You need to include the Google Play Services Location library to be able to access the location services. The maps library is optional since you done need to access the location updates, but in our case we shall be showing the updates on a map thus we include as well.
Permissions
Location permissions
If your app needs to access the user’s location, you must request permission by adding the relevant Android location permission to your app.
Android offers two location permissions: ACCESS_COARSE_LOCATION
and ACCESS_FINE_LOCATION
. The permission you choose determines the accuracy of the location returned by the API. You only need to request oneof the Android location permissions, depending on the level of accuracy you need:
android.permission.ACCESS_COARSE_LOCATION
– Allows the API to use WiFi or mobile cell data (or both) to determine the device’s location. The API returns the location with an accuracy approximately equivalent to a city block.android.permission.ACCESS_FINE_LOCATION
– Allows the API to determine as precise a location as possible from the available location providers, including the Global Positioning System (GPS) as well as WiFi and mobile cell data.
1 2 3 4 5 6 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" > ... <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> ... </manifest> |
External storage permission
If you’re targeting version 8.3 or later of the Google Play services SDK, you no longer need the WRITE_EXTERNAL_STORAGE
permission to use the Google Maps Android API. If you’re targeting earlier versions of the Google Play services SDK, you must request theandroid.permission.WRITE_EXTERNAL_STORAGE
permission.
1 2 |
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
Note: If your app is targeting API level 23 (Android 6.0), which requires the use of runtime permissions, you shouldtarget version 8.3 or later of the Google Play services SDK.
Permissions automatically merged into your manifest
The following permissions are defined in the Google Play services manifest, and are automatically merged into your app’s manifest at build time. You don’t need to add them explicitly to your manifest:
android.permission.INTERNET
– Used by the API to download map tiles from Google Maps servers.android.permission.ACCESS_NETWORK_STATE
– Allows the API to check the connection status in order to determine whether data can be downloaded.
Google Api Client
The main entry point for Google Play services integration. Before any operation is executed, the GoogleApiClient must be connected. It has the following nested classes…
class | GoogleApiClient.Builder | Builder to configure a GoogleApiClient . |
|
interface | GoogleApiClient.ConnectionCallbacks | Provides callbacks that are called when the client is connected or disconnected from the service. | |
interface | GoogleApiClient.OnConnectionFailedListener | Provides callbacks for scenarios that result in a failed attempt to connect the client to the service. |
Location Listener
Implement the LocationListener
interface and define theLocationListener.onLocationChanged()
callback method. The fused location provider invokes this method.
1 2 3 4 5 6 7 8 9 10 |
public class LocationUpdates extends AppCompatActivity implements LocationListener, OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { ... } |
……
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 |
protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); createLocationRequest(); } protected void createLocationRequest() { mLocationRequest = new LocationRequest(); // Sets the desired interval for active location updates. This interval is // inexact. You may not receive updates at all if no location sources are available, or // you may receive them slower than requested. You may also receive updates faster than // requested if other applications are requesting location at a faster interval. mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); // Sets the fastest rate for active location updates. This interval is exact, and your // application will never receive updates faster than this value. mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); //LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } |
….
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 |
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_location); latitude = (TextView) findViewById(R.id.latitude); longitude = (TextView) findViewById(R.id.longitude); updateTime = (TextView) findViewById(R.id.updateTime); LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { enableGpsAlert(); } // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); buildGoogleApiClient(); } @Override protected void onStart() { super.onStart(); mGoogleApiClient.connect(); } @Override protected void onPause() { super.onPause(); // Stop location updates to save battery, but don't disconnect the GoogleApiClient object. if (mGoogleApiClient.isConnected()) { stopLocationUpdates(); } } @Override protected void onResume() { super.onResume(); if (mGoogleApiClient.isConnected()) { startLocationUpdates(); } } @Override protected void onStop() { mGoogleApiClient.disconnect(); super.onStop(); } |
Get the Last Known Location
You want to start off getting the last known location of your device before you start receiving periodic location updates. Using Google Play Services location APIs, your app can request the last known location of the user’s device.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Override public void onConnected(@Nullable Bundle bundle) { if (mCurrentLocation == null) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) { return; } mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); if (mCurrentLocation != null) { // bse this may not be got if you've never used location service // causing a null pointer exception updateUI(); } } startLocationUpdates(); } |
Request Location Updates
In most cases, you are interested in the user’s current location, which is usually equivalent to the last known location of the device.
1 2 3 4 5 6 7 8 9 |
protected void startLocationUpdates() { // The final argument to {@code requestLocationUpdates()} is a LocationListener // (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html). if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) { return; } LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); } |
Define the Location Update Callback
1 2 3 4 5 6 |
@Override public void onLocationChanged(Location location) { mCurrentLocation = location; mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); updateUI(); } |
Stop Location Updates
1 2 3 4 5 6 7 8 9 |
protected void stopLocationUpdates() { // It is a good practice to remove location requests when the activity is in a paused or // stopped state. Doing so helps battery performance and is especially // recommended in applications that request frequent location updates. // The final argument to {@code requestLocationUpdates()} is a LocationListener // (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html). LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); } |
Update UI to show ‘new’ current location
1 2 3 4 |
protected void updateUI() { LatLng latLng = new LatLng(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude()); mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); } |