Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making the Fused Location Provider LocationClient easier to use

Let's say I have 5 different activities in my app that wish to use LocationClient.getLastLocation() to get the last known location. This seems simple.

Ideally, I would just create a LocationClient in each activity and call getLastLocation(). However, there's some additional work one has to do to connect to the Google Play Services, such as call LocationClient.connect() and handle the onConnected, onDisconnected, and onConnectionFailed callbacks. The documentation is here: https://developer.android.com/training/location/retrieve-current.html

As far as I can tell, each of my five different activities must all handle the lifecycle methods of the LocationClient. They also can't call getLastLocation() right away in onCreate() because the connection for that activity may not have been established yet.

Is there an easy way to simplify the lifecycle of the LocationClient so that getLastLocation() will work right away in any new activity once I get the connection established once for my app?

like image 324
emmby Avatar asked Jan 07 '14 00:01

emmby


People also ask

How does a fused location provider work?

The fused location provider manages the underlying location technologies, such as GPS and Wi-Fi, and provides a simple API that you can use to specify the required quality of service. For example, you can request the most accurate data available, or the best accuracy possible with no additional power consumption.

What is FusedLocationProviderClient android?

FusedLocationProviderClient is for interacting with the location using fused location provider. (NOTE : To use this feature, GPS must be turned on your device.

How accurate is fused location provider?

Accuracy of defined location varies based on number of visible satellites, device hardware and environment. Usually it's about 3m in case if there are no high buildings or metallic structures (hiding satellites from your device sight) around.


2 Answers

If you are familiar with the reactive-programming, you have to try the RxLocation library, which wrapped the Fused API into the RX way.

Example:

// Create one instance and share it
RxLocation rxLocation = new RxLocation(context);

LocationRequest locationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(5000);

rxLocation.location().updates(locationRequest)
        .flatMap(location -> rxLocation.geocoding().fromLocation(location).toObservable())
        .subscribe(address -> {
            /* do something */
        });
like image 174
Shawn Lu Avatar answered Oct 23 '22 06:10

Shawn Lu


I have used fused location provider APIs to get periodic location updates. I have implemented it inside a background service (e.g. LocationUpdateService extends Service). Earlier I was using Android Location framework APIs but it's not good for battery usage. Fused Location Provider APIs are the best for efficient battery usage.

I have also prepared a notes of steps which are necessary to implement it (along with other useful information). In simple words, it's the best way to get location data in Android platform as of now. Google Play Services provide many location APIs to get the location data (e.g. user’s current location or you can say device’s last known location).

The Fused Location Provider is one of the location APIs in Google Play services. These are the prerequisites:

  1. Google Play services SDK is used as library project (and also Google PlayService is properly installed in your device).

    • Download and install the Google Play services component from the SDK Manager and add the library to your project.
    • Import the GooglePlayServices library from android google-play-services_lib in your development project as Library project.
  2. You should have an actual device as this API won't work in the emulator.

The Fused Location Provider intelligently manages the underlying location technology (GPS/Wi-Fi/Network provider’s connection) and gives us the best location according to our needs.

Why use it

We could choose one of the location providers (network or GPS) and request location updates or set up proximity alert. But there were two main issues with this approach: 1. In case we need to define precise location, we had to switch between network and GPS location providers (as GPS doesn’t work indoors). 2. Proximity alerts were used to notify a user about proximity to a location, and this took its toll on the battery life.

Benefits

  1. Simple APIs: It let's us specify high-level needs like “high accuracy” or “low power”, instead of having to worry about location providers.
  2. Battery efficient: It minimizes the app power usage. Based on all incoming location requests and available sensors, fused location provider chooses the most efficient way to meet those needs.

Steps to use this API:

  1. Declare the location related permission in the manifest file.

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    

    Or

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    
  2. Implement related interfaces and callbacks. Before we request location updates, we must first implement the interfaces that Location Services uses to communicate connection status to our app:

    • com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks: Specifies methods that Location Services calls when a location client is connected or disconnected.
    • com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener
  3. Connect to Google Play Services, connecting LocationClient to the Google API. To do this, create a LocationClient object (instance of GoogleApiClient) as:

    mLocationClient = new GoogleApiClient.Builder(getApplicationContext())
        .addApi(LocationServices.API).addConnectionCallbacks(this)
        .addOnConnectionFailedListener(this).build();
    

    And then call mLocationClient.connect();.

  4. Create an instance of FusedLocationProviderApi by using the LocationServices class as:

    private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
    
  5. Retrieve the current location inside onConnected(Bundle bundle):

    Location currentLocation = fusedLocationProviderApi                                  .getLastLocation(mLocationClient);
    if (mCurrentLocation != null) {
        Log.d(TAG, "last location = " + mCurrentLocation.getLatitude() +
            " - " + mCurrentLocation.getLongitude());
    }           
    
  6. Create and setup a LocationRequest object:

    mLocationRequest = new LocationRequest();
    
    private void setLocationParameter() {
        // Set the update interval
        mLocationRequest.setInterval(Constants.SECONDS_TO_UP);
        // Use high accuracy
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        // Set the interval ceiling to one minute
        mLocationRequest.setFastestInterval(Constants.SECONDS_TO_UP);
        // Set the distance to 10 meters.
        mLocationRequest.setSmallestDisplacement(Constants.METERS_TO_UP);
    }
    
  7. To get periodic location updates from Location Services, we send a request using a location client.

    LocationListener listener =  new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {    
            Utils.locationUpdates = Utils.locationUpdates + 1;
            if (Utils.locationUpdates == 1) {
                mLocationRequest .setPriority(LocationRequest.PRIORITY_LOW_POWER);
                LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, mLocationRequest, listener);
            }
        }
    };
    
like image 39
amarnathpatel Avatar answered Oct 23 '22 07:10

amarnathpatel