Android: Google Maps Location with Low Battery Usage

Android: Google Maps location with low battery usage

FINALLY FOUND THE SOLUTION!!!
thanks to Tristan for his answer!

By default, GoogleMap uses its on location provider, which is not the Fused Location Provider. In order to use the Fused Location Provider (which allows you to control the location accuracy and power consumption) you need to explicitely set the map location source with GoogleMap.setLocationSource() (documentation)

I am reporting here a sample activity to do that:

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;

import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends FragmentActivity
implements
ConnectionCallbacks,
OnConnectionFailedListener,
LocationSource,
LocationListener,
OnMyLocationButtonClickListener,
OnMapReadyCallback {

private GoogleApiClient mGoogleApiClient;
private TextView mMessageView;
private OnLocationChangedListener mMapLocationListener = null;

// location accuracy settings
private static final LocationRequest REQUEST = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMessageView = (TextView) findViewById(R.id.message_text);

SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);

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

}

@Override
protected void onResume() {
super.onResume();
mGoogleApiClient.connect();
}

@Override
public void onPause() {
super.onPause();
mGoogleApiClient.disconnect();
}

@Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
}

public void showMyLocation(View view) {
if (mGoogleApiClient.isConnected()) {
String msg = "Location = "
+ LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
}

/**
* Implementation of {@link LocationListener}.
*/
@Override
public void onLocationChanged(Location location) {
mMessageView.setText("Location = " + location);
if (mMapLocationListener != null) {
mMapLocationListener.onLocationChanged(location);
}
}

@Override
public void onConnected(Bundle connectionHint) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
REQUEST,
this); // LocationListener
}

@Override
public void onConnectionSuspended(int cause) {
// Do nothing
}

@Override
public void onConnectionFailed(ConnectionResult result) {
// Do nothing
}

@Override
public boolean onMyLocationButtonClick() {
Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show();
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
return false;
}

@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mMapLocationListener = onLocationChangedListener;
}

@Override
public void deactivate() {
mMapLocationListener = null;
}
}

Get location (coordinates) periodically without dramatically increase battery consumption

If you are worried about battery and not so stricted on the 10 minutes interval you could try to use PassiveProvider instead of GPS/Coarse.

Usually other applications request locations often enough so you don't need to worry about it.

If you are strict, than you could try to ask for location yourself in case one hasn't received in the past interval.

Here is an example for using the Passive Provider.

LocationManager locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}

@Override
public void onProviderEnabled(String provider) {}

@Override
public void onProviderDisabled(String provider) {}

@Override
public void onLocationChanged(Location location) {
// Do work with new location. Implementation of this method will be covered later.
doWorkWithNewLocation(location);
}
};

long minTime = 10*60*1000;
long minDistance = 0;

locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, minTime, minDistance, locationListener);

setMyLocationEnabled(true) is unresponsive, slow refresh rate

You can change the location provider for the My location layer using the method map.setLocationSource(). That's the only tweak (besides enabling and disabling it) that you can do to the My Location layer.

You can find a working example using the Fused Location Provider here: Android: Google Maps location with low battery usage

Another option could be to replace the My Location layer with your own marker for better control on the layer as explained here: Google Maps: Current Location Marker (Period updates for GMaps)

Battery impact of polling for location updates less often?

For Fused Location API, I'm not certain if they turn off GPS or adjust reporting interval while leaving it on, but I would assume they turn off GPS between updates, or else many others would complain about power drain.

As for what Android Location Service does, they do turn off GPS and allow the phone to idle between updates if the interval is greater than 0 (check out the source in LocationManagerService). I've done quite a bit of power testing on different android phones, and found that keeping the CPU from idling can draw a noticeable amount of power. Add the power draw of GPS (which keeps the CPU from idling) and you are looking at a decent power drain (about 50% of what the screen would draw for some devices).

In the end, I'd have to agree with Gabe Sechan and advise you on choosing whether accuracy is worth the battery drain. Just ask yourself these basic questions:

  • Do I need to know if my user is on one side of the street or the other?

    If yes, use GPS, else use Network or low accuracy location.

  • How often do I need to check my user's location?

    If you need it about once a minute, set your interval as such. If you only care when they leave a general area, setup a geofence, or use network locations. You can also listen to location updates from other apps, and make your app smarter about when to take updates.

  • If I can't get my user's location within X amount of time, can I skip this update altogether?

    If you can, then put a timeout feature in your update logic. If not, I strongly recommend you re-evaluate the app logic in that case.

will geofence reduce power consumption vs just checking location every x seconds?

The way Android is handling geofencing is quite complex. There are many differences between devices, but also between Android versions. But as a quick answer, your solution could save battery, because detecting a zone exit don't necessarily require GPS, but could use other location methods like Cell ID or Wifi, which are much less battery consuming. You also need to know that geofencing is not a 100% reliability solution, in particularly on Zone Exit events (less than 50% of zone exits detected in average), that are less reliable than Zone Enter events. Some companies like Herow, Radar, Foursquare are building SDKs that manage specifically geofencing.

Does Google Maps Android API locate me automatically?

Try to use

googleMap.setMyLocationEnabled(true/false);

to control showing your location on map. I think it is enough to turn the setting on to make your location work with Google Maps, without need to use LocationManager etc.

Even if my android app destroy, com.google.android.gms drain battery

you need to remove the updates. It will work in other thread
Try this:

@Override
public void onDestroy() {
locationManager.removeUpdates(this);
super.onDestroy();
}


Related Topics



Leave a reply



Submit