Android: местоположение Google Maps с низким расходом заряда батареи

Мое приложение в настоящее время использует Карты от Google Play Services

спецификация:

mMap.setMyLocationEnabled(true);

Я понимаю каждый раз, когда показываю карту в своем приложении:

  • место указано на карте синей точкой
  • значок местоположения отображается на верхней панели
  • если я захожу в Настройки/Местоположение телефона, мое приложение сообщается как "Высокое использование батареи"

Тем не менее, я вижу, что есть приложения, которые используют Карты и по-прежнему показывают синюю точку местоположения, но значок местоположения не появляется на верхней панели, а их заряд батареи низкий.

В настоящее время мое приложение предоставляет оба разрешения:

  • android.permission.ACCESS_COARSE_LOCATION
  • android.permission.ACCESS_FINE_LOCATION

Мой вопрос:

как я могу показать синюю точку местоположения при низком уровне заряда батареи?

можно ли указать точность/использование батареи по коду?

ОБНОВЛЕНИЕ

На самом деле я понял, что способ сделать это - использовать GoogleApiClient FusedLocationApi

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

Я настроил GoogleApiClient внутри своей деятельности, вызвав:

  • GoogleApiClient.connect() в начале Активности
  • GoogleApiClient.disconnect() на остановке мероприятия

в обратном вызове onConnected я установил критерии для обновления местоположения: самый быстрый интервал в 1 минуту с низким приоритетом мощности:

    private static final LocationRequest REQUEST = LocationRequest.create()
        .setFastestInterval(60000)   // in milliseconds
        .setInterval(180000)         // in milliseconds
        .setPriority(LocationRequest.PRIORITY_LOW_POWER);

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

Я проверил, что GoogleApiClient правильно подключается при запуске, но по некоторым причинам всякий раз, когда я посещаю фрагмент со встроенным MapView, я все еще получаю высокое использование батареи для моего приложения на экране настроек/местоположения!

Кажется, что MapView игнорирует эти критерии низкого энергопотребления!


comment
вам не нужны оба этих разрешения, выберите одно из них   -  person Marian Paździoch    schedule 23.01.2015
comment
Я вижу приложения, которые запрашивали оба разрешения, но при этом могут показывать местоположение синими точками при низком уровне заряда батареи. Интересно, есть ли способ программно установить точность в коде.   -  person Daniele B    schedule 23.01.2015
comment
Тогда какой у тебя вопрос?   -  person Marian Paździoch    schedule 23.01.2015
comment
мой вопрос в том, как по-прежнему показывать местоположение с низким использованием батареи   -  person Daniele B    schedule 23.01.2015
comment
поэтому, пожалуйста, отредактируйте свой вопрос   -  person Marian Paździoch    schedule 23.01.2015
comment
@MarianPaździoch, я обновил вопрос и назначу награду в размере +50 за правильный ответ.   -  person Daniele B    schedule 26.01.2015


Ответы (4)


НАКОНЕЦ-ТО НАШЕЛ РЕШЕНИЕ!!! спасибо Тристану за его ответ!

По умолчанию GoogleMap использует своего поставщика местоположения, который не является поставщиком объединенного местоположения. Чтобы использовать Fused Location Provider (который позволяет вам контролировать точность определения местоположения и энергопотребление), вам необходимо явно указать источник местоположения карты с помощью GoogleMap.setLocationSource() (документация)

Я сообщаю здесь образец действия для этого:

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;
    }
}
person Daniele B    schedule 26.01.2015
comment
Забавно, это именно MyLocationDemo из образцов google-play-services, которые поставляются с SDK. У вас просто есть интерфейс LocationSource. Хорошая вещь. - person Davi Alves; 28.03.2015
comment
У меня вопрос когда деактивируется называется - person krishna; 31.03.2015
comment
Я назначил награду Тристану, но я сообщил об этом вопросе как об ответе, поскольку он представляет собой полный рабочий пример. - person Daniele B; 26.05.2015

Вы захотите, чтобы ваша деятельность (или лучше отдельный объект для этой цели) реализовывала LocationSource.

Это довольно просто: вам нужно сохранить прослушиватель, переданный в методе activate(), и вызвать его, когда местоположение будет обновлено, и забыть о нем, когда вызывается deactivate(). См. этот ответ для примера, вы, вероятно, захотите обновить его, чтобы использовать FusedLocationProvider.

После того, как вы настроите эту настройку, вы можете передать свою активность как LocationSource для карты, например mMap.setLocationSource(this) (документация).

Это предотвратит использование карты по умолчанию LocationSource, которая использует службы определения местоположения с высоким расходом заряда батареи.

person Tristan Burnside    schedule 26.01.2015
comment
Смотрите мой ответ, в нем говорится, что источником местоположения по умолчанию действительно является FusedLocationProvider, поэтому нет необходимости устанавливать его снова. - person Marian Paździoch; 26.01.2015
comment
Он установлен, но не установлен на LocationRequest.PRIORITY_LOW_POWER - person Tristan Burnside; 26.01.2015
comment
Большое спасибо, Тристан, это правильный ответ!!!! Вы выиграли награду в 50 очков!!!! кажется, что Карты Google по умолчанию используют собственный источник местоположения, который не является FusedLocationProvider. Поэтому необходимо явно установить FusedLocationProvider, если вы хотите контролировать точность. - person Daniele B; 26.01.2015

здесь указано, что

FusedLocationProviderApi обеспечивает улучшенное определение местоположения и энергопотребление и используется синей точкой «Мое местоположение».

Таким образом, точка «Мое местоположение» на карте питается от FusedLocationProviderApi. И когда вы предоставляете разрешение android.permission.ACCESS_FINE_LOCATION, вы разрешаете FusedLocationProviderApi своему приложению получать данные от GPS, что может привести к высокому расходу заряда батареи.

Поэтому добавьте только android.permission.ACCESS_COARSE_LOCATION разрешение на манифест, и Android не будет обвинять вас в расходе заряда батареи.

person Marian Paździoch    schedule 23.01.2015
comment
к сожалению, невозможно удалить разрешение android.permission.ACCESS_FINE_LOCATION: stackoverflow.com/questions/17089141/ - person Daniele B; 26.01.2015
comment
точка местоположения на карте на самом деле не питается FusedLocationProvider по умолчанию. Вам необходимо явно указать источник местоположения карты для получения данных из FusedLocationProvider - person Daniele B; 26.01.2015

Вы можете сделать это, используя классы сетевых провайдеров. Вы можете использовать приведенный ниже код AppLocationService.java//Специально для получения текущего местоположения с низким уровнем использования батареи (так же, как режим экономии заряда батареи в 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;
}

}

Использование вышеуказанного класса MainActivity.java

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

                        }

Таким образом, вы можете получить текущее местоположение с помощью режима GPS в режиме высокого качества использования, после того как вы можете установить синюю точку или что угодно.

Надеюсь, это поможет вам и всем

person Kirtikumar A.    schedule 23.01.2015
comment
это не ответ на заданный вопрос - person Marian Paździoch; 23.01.2015
comment
@Как ты можешь такое говорить? Есть ли что-нибудь, что вы знаете? - person Kirtikumar A.; 23.01.2015