In wayfinding applications you may not want to keep your application positioning all the time. Imagine this situation:  the user opens the map and you start positioning,  then she closes it and you a stop, but just after a few seconds, she opens the app again and you need to start positioning. 


The problem is that each time Situm SDK will need to start positioning from scratch after each re-start, therefore requiring a few seconds each time to provide an accurate location. For the user, this makes no sense: after all, she was perfectly located a few seconds ago, and she didn't move!


To solve this issue, Situm SDK provides an option that can be activated using the method LocationRequest.Builder.useLocationsCache. In essence, this option saves the last know location in the smartphone's cache and uses it at a hint when you start positioning, provided that this last known location is not older than 30 seconds.


If the user did not move significantly since the last stop, Situm SDk will provide a first accurate location almost inmediatelly. Otherwise, behaviour may change as described in the following table.


User moved from last stored locationExpected behaviour
0 meters - 5 metersAn accurate location will be provided inmediatelly
10 meters-20 metersAn approximate location will be provided inmediatelly (error = 10-20 meters). It will regain the usual accuracy after a few seconds, specially if the user moves
20-50 metersA not so accurate location will be provided inmediatelly (error = 20-50 meters). Situm SDK will probably try to geolocate the user again from scratch, resulting in a beheviour similar to what's expected when this option is not active.


The user may also change her orientation since the last know location. This table describes what to expect in this case:


User orientation changed from last stored location
Smartphone has a working compass (calibrated)Expected behaviour

User does not change orientation or turns right/left less than 45 degreesYesAn accurate orientation will be provided quickly.
NoOrientation will be accurate enough very quickly (+-45 degrees of maximum error). 
Otherwise
YesAn unaccurate orientation (error over +-45 degrees) will be provided at first. Situm SDK will re-compute an accurate orientation in a few seconds.
NoAn unaccurate orientation (error over +-45 degrees) will be provided at first. In order to achieve better accuracy, user may have to walk around.


Code example


The following code example shows how to use this method. In this example, we create two buttons to Start and Stop the positioning system (just for the sake of the example). The buttons are defined in your activity_main.xml file:


<?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=".MainActivity">

    <!-- Start Button -->
    <Button
        android:id="@+id/button_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:text="Start"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- Stop Button -->
    <Button
        android:id="@+id/button_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
        android:text="Stop"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>


Then, in your MainActivity.java


package com.example.situmsdkbasicapp;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;


import es.situm.sdk.SitumSdk;
import es.situm.sdk.location.LocationListener;
import es.situm.sdk.location.LocationRequest;
import es.situm.sdk.location.LocationStatus;
import es.situm.sdk.model.location.Location;
import es.situm.sdk.error.Error;



public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    private Button buttonStart, buttonStop;

    private LocationListener locationListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            Log.i(TAG, "onLocationChanged() called with: location = [" + location + "]");
        }

        @Override
        public void onStatusChanged(@NonNull LocationStatus status) {
            Log.i(TAG, "onStatusChanged() called with: status = [" + status + "]");
        }

        @Override
        public void onError(@NonNull Error error) {
            Log.e(TAG, "onError() called with: error = [" + error.getMessage() + "]" + " and code = ["+error.getCode() + "]");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //Initializes Situm SDK
        SitumSdk.init(this);

        //Creates the LocationRequest with the Locations Cache activated
        final LocationRequest locationRequest = new LocationRequest.Builder().useLocationsCache(true).build();

        //Start Button: starts positioning
        buttonStart = (Button) findViewById(R.id.button_start);
        buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!SitumSdk.locationManager().isRunning()) SitumSdk.locationManager().requestLocationUpdates(locationRequest, locationListener);
            }
        });

        //Stop Button: stops positioning
        buttonStop = (Button) findViewById(R.id.button_stop);
        buttonStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (SitumSdk.locationManager().isRunning()) SitumSdk.locationManager().removeUpdates(locationListener);
            }
        });
    }
}


Execution


If you build & run this example, your application log should look like this:


2021-04-10 13:41:48.190 onStatusChanged() called with: status = [CALCULATING]
2021-04-10 13:41:51.196 onStatusChanged() called with: status = [STARTING]
2021-04-10 13:41:52.292 onLocationChanged() called with: location = [Location{provider='SITUM_PROVIDER', deviceId=724614936937, timestamp=1618054912258, position=Point{buildingIdentifier='-1', floorIdentifier='-1', cartesianCoordinate=CartesianCoordinate{x=0.00, y=0.00}, coordinate=Coordinate{latitude=43.356493, longitude=-8.413401}, isOutdoor=true}, quality=HIGH, accuracy=22.846, cartesianBearing=Angle{radians=0.00, degrees=0.00}, bearing=Angle{radians=0.00, degrees=0.00}, bearingQuality=HIGH, customFields={}}]

....

2021-04-10 13:42:02.034 onLocationChanged() called with: location = [Location{provider='SITUM_PROVIDER', deviceId=724614936937, timestamp=1618054921993, position=Point{buildingIdentifier='6541', floorIdentifier='13483', cartesianCoordinate=CartesianCoordinate{x=14.02, y=8.57}, coordinate=Coordinate{latitude=43.356419, longitude=-8.413083}, isOutdoor=false}, quality=HIGH, accuracy=2.5115864, cartesianBearing=Angle{radians=3.06, degrees=175.46}, bearing=Angle{radians=4.79, degrees=274.54}, bearingQuality=LOW, customFields={}}]


At this point, Situm SDK has converged to an accurate location in building 6541, floor 13483, latitude 43.356419 and longitued -8.413083. If you hit the Stop button, Situm SDK will will stop but, if you hit the Start button again (before 30 seconds), the last known location will be uset at startup again.


2021-04-10 13:42:02.280 onStatusChanged() called with: status = [STOPPED]
2021-04-10 13:42:04.630 onStatusChanged() called with: status = [CALCULATING]
2021-04-10 13:42:05.686 onStatusChanged() called with: status = [STARTING]
2021-04-10 13:42:07.691 onLocationChanged() called with: location = [Location{provider='SITUM_PROVIDER', deviceId=724614936937, timestamp=1618054927396, position=Point{buildingIdentifier='6541', floorIdentifier='13483', cartesianCoordinate=CartesianCoordinate{x=14.02, y=8.57}, coordinate=Coordinate{latitude=43.356419, longitude=-8.413083}, isOutdoor=false}, quality=LOW, accuracy=0.0, cartesianBearing=Angle{radians=3.06, degrees=175.46}, bearing=Angle{radians=4.79, degrees=274.54}, bearingQuality=LOW, customFields={}}]
...


Notice that the last know location is exactly repeated in the first geolocations provided by the SDK after the re-start, in just a few seconds. After a few seconds, the SDK starts integrating sensor data as usual and new locations will be computed.