Можно ли получить уведомление, когда какой-либо провайдер местоположения включен/отключен, и выяснить, какое действие произошло?

Я хочу получать уведомление, когда пользователь включает или отключает местоположение сети или GPS, и, что важно, я хочу знать, какое из них они изменили и как. У меня есть широковещательный приемник для широковещательного намерения android.location.PROVIDERS_CHANGED, и он получает правильную широковещательную рассылку.

Теперь мне нужно попытаться определить, какое действие произошло, т. е. включить или отключить, и какой провайдер был изменен. Я знаю, что могу сохранить состояние каждого провайдера, а затем, когда я получу уведомление о том, что они изменились, я смогу выяснить, что изменилось, я ищу более «стандартный» способ сделать это. Похоже, что в широковещательном намерении нет никаких дополнений, указывающих, какой провайдер изменился.

Это код, который у меня есть в настоящее время.

    public class LocationProviderChangedReceiver extends BroadcastReceiver {
    private final static String TAG = "LocationProviderChangedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
      if (intent.getAction().matches("android.location.PROVIDERS_CHANGED"))
      {
        Log.i(TAG,"Location Providers changed");
        Bundle bundle = intent.getExtras();
        if (bundle == null) {
          Log.d(TAG, "No extras data");
         } else {
           Log.d(TAG, "Bundle received of size " + bundle.size);
         } 
      }
    }
  }

А это небольшая выдержка из моего манифеста

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

  <receiver 
    android:name=".LocationProviderChangedReceiver"
    android:exported="false">
    <intent-filter>
      <action android:name="android.location.PROVIDERS_CHANGED" />
      <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
  </receiver>

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

В идеальном мире я бы постоянно следил за изменениями, но лишь изредка прислушивался к изменениям местоположения. Я хотел бы избежать постоянного отслеживания изменений местоположения.


person Steve Weet    schedule 09.04.2013    source источник


Ответы (4)


Я надеюсь, что это не противоречит вашему требованию

Я знаю, что могу сохранить состояние каждого провайдера, а затем, когда я получу уведомление о том, что они изменились, я смогу выяснить, что изменилось, я ищу более «стандартный» способ сделать это.

... но я думаю, что лучший, "стандартный" и наиболее гибкий способ сделать это - позволить вашему LocationProviderChangedReceiver реализовать LocationListener, а затем реализовать onProviderEnabled() и onProviderDisabled() следующим образом:

public void onProviderEnabled(String provider) {
  if(provider.equals(LocationManager.GPS_PROVIDER)){
    ...
  } else if (provider.equals(LocationManager.NETWORK_PROVIDER)){
    ...
  }
}

Обратите внимание, что вы должны добавить разрешение ACCESS_FINE_LOCATION в свой манифест, если вы еще этого не сделали. Кроме того, в зависимости от контекста могут применяться другие поставщики (помимо «Сети» и «GPS»), например PASSIVE_PROVIDER или даже FUSED_PROVIDER.

Обновленный ответ:
Если вам не подходит постоянное прослушивание изменений местоположения, LocationManager также знает какой провайдер сейчас включен:

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

...чтобы вы могли использовать эти проверки вместе с вашим BroadcastReceiver, чтобы избежать ручного удержания каких-либо включенных/отключенных флагов. Помимо этого, есть намерение, называемое android.location.GPS_ENABLED_CHANGE, которые вы также можете попытаться получить (и обработать). Но поскольку это намерение скрыто в официальной документации, его использование может быть небезопасным, как указано в этом ответе.

Еще один подход:
виджет переключения настроек Android по умолчанию (вы понимаете, что я имею в виду) отображает включенное/отключенное состояние GPS путем подписки на намерение android.location.PROVIDERS_CHANGED (как и вы) для запуска запроса Состояние GPS через пользовательские настройки:

@Override
public int getActualState(Context context) {
  ContentResolver resolver = context.getContentResolver();
  boolean on = Settings.Secure.isLocationProviderEnabled(
                 resolver, LocationManager.GPS_PROVIDER);
  return on ? STATE_ENABLED : STATE_DISABLED;
}

(из официальных источников).
Этот подход можно адаптировать и для других провайдеров геолокации.

person saschoar    schedule 09.04.2013
comment
Извините, что изменил вопрос и требования после того, как вы ответили, но я искал способ контролировать это, не прослушивая местоположения. Я запрашиваю обновления местоположения в разных точках, но я хотел постоянно отслеживать изменения в провайдерах, не прослушивая постоянно местоположения. - person Steve Weet; 10.04.2013
comment
Хорошо, в этом случае также может помочь LocationManager. Я обновил свой ответ. - person saschoar; 10.04.2013

Это работает для меня:

Добавьте приемник в файл манифеста:

<receiver
        android:name="com.eegeo.location.LocationProviderChangedReceiver">
        <intent-filter>
            <action android:name="android.location.PROVIDERS_CHANGED" />
        </intent-filter>
    </receiver>

Проверьте обоих провайдеров местоположения в приемнике:

public class LocationProviderChangedReceiver  extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {

        boolean anyLocationProv = false;
        LocationManager locationManager = (LocationManager) MyMainActivity.context.getSystemService(Context.LOCATION_SERVICE);

        anyLocationProv |= locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        anyLocationProv |=  locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        Log.i("", "Location service status" + anyLocationProv);


    }

}

Хотя этот приемник вызывается более одного раза по понятным причинам, но это сообщит вам статус.

person M. Usman Khan    schedule 11.03.2015

Благодаря ответу @usman мы можем применить решение без extends класса следующим образом;

AndroidManifest.xml;

<receiver android:name="com.eegeo.location.LocationProviderChangedReceiver">
    <intent-filter>
        <action android:name="android.location.PROVIDERS_CHANGED" />
    </intent-filter>
</receiver>

class (я никогда не тестировал);

public class LocationProviderChangedReceiver {

    private mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String ability = (isGPSProviderEnabled() && isNetworkProviderEnabled()) ? "CAN" : "CANNOT";
            Log.d("", "The location " + ability + " be caught in high accuracy!");
        }
    };


    public startProviderChangeObserving () {
        registerReceiver(mReceiver, new IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION));

    }


    public stopProviderChangeObserving () {
        unregisterReceiver(mReceiver);
    }   


    /**
    * Method to verify that the location providers wheter on or not on the device
    **/
    public boolean isGPSProviderEnabled() {
        return (Boolean) mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }

    public boolean isNetworkProviderEnabled() {
        return (Boolean) mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    }

}
person efkan    schedule 08.09.2016

На приемнике вы можете просто проверить, какие провайдеры включены:

LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE)
List<String> providers = lm.getProviders(true);

Таким образом, вы получаете всех разрешающих провайдеров.

person Antonio Romano    schedule 30.09.2014