Android: Google Maps location with low battery usage

前端 未结 4 1296
遥遥无期
遥遥无期 2020-11-30 01:39

My app is currently using Maps by Google Play Services

speficying:

mMap.setMyLocationEnabled(true);

I realize each time I a

相关标签:
4条回答
  • 2020-11-30 01:57

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-30 02:11

    You will want to make your activity (or better a separate object for this purpose) implement the LocationSource interface.

    It is pretty simple you need to store the listener passed in the activate() method and call it when the location is updated and forget it when deactivate() is called. See this answer for an example, you will probably want to update it to use the FusedLocationProvider.

    Once you have this set up you can pass your activity as the LocationSource for the map like so mMap.setLocationSource(this) (documentation).

    This will stop the map from using its default LocationSource which uses the high battery use location services.

    0 讨论(0)
  • 2020-11-30 02:16

    It's stated here that

    FusedLocationProviderApi provides improved location finding and power usage and is used by the "My Location" blue dot.

    So "My Location" dot on map is fed by FusedLocationProviderApi. And as you grant permission android.permission.ACCESS_FINE_LOCATION you allow FusedLocationProviderApi for your app to get data from GPS which may cause high battery use.

    So add only android.permission.ACCESS_COARSE_LOCATION permission to manifest and Android should not blame you for battery usage.

    0 讨论(0)
  • 2020-11-30 02:16

    You can do so by using Network provider classes You can use below code AppLocationService.java // Special for getting current location with low battery usage (same like Battery saver mode in nexus 5 ,5.0)

    package coreclass;
    
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.location.Location;
    import android.location.LocationListener;
    import android.location.LocationManager;
    import android.os.Bundle;
    import android.os.IBinder;
    
    public class AppLocationService extends Service implements LocationListener {
    
    protected LocationManager locationManager;
    Location location;
    
    private static final long MIN_DISTANCE_FOR_UPDATE = 10;
    private static final long MIN_TIME_FOR_UPDATE = 1000 * 60 * 2;
    
    public AppLocationService(Context context) {
        locationManager = (LocationManager) context
                .getSystemService(LOCATION_SERVICE);
    }
    
    public Location getLocation(String provider) {
        if (locationManager.isProviderEnabled(provider)) {
            locationManager.requestLocationUpdates(provider,
                    MIN_TIME_FOR_UPDATE, MIN_DISTANCE_FOR_UPDATE, this);
            if (locationManager != null) {
                location = locationManager.getLastKnownLocation(provider);
                return location;
            }
        }
        return null;
    }
    
    @Override
    public void onLocationChanged(Location location) {
    }
    
    @Override
    public void onProviderDisabled(String provider) {
    }
    
    @Override
    public void onProviderEnabled(String provider) {
    }
    
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }
    
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
    
    }
    

    Usage of above class MainActivity.java

    AppLocationService appLocationService;
    appLocationService = new AppLocationService(getActivity());
    Location nwLocation = appLocationService.getLocation(LocationManager.NETWORK_PROVIDER);
                            if (nwLocation != null) {
                                Lat = nwLocation.getLatitude();
                                Longi = nwLocation.getLongitude();
    
                            }
    

    In this way you can get the current location with GPS mode in high bettery usage mode, after you can set the blue dot or whatever you want

    Hope it helps you and all

    0 讨论(0)
提交回复
热议问题