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

Я хочу получать уведомление, когда пользователь включает или отключает местоположение сети или 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> 

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

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

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

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

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

… но я думаю, что лучший, «стандартный» и самый гибкий способ сделать это – позволить вашему 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; } 

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

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

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

 <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); } } 

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

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

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

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

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

AndroidManifest.xml;

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

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

 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); } }