是否可以在启用/禁用任何位置提供程序时获取通知并确定发生了什么操作?

时间:2013-04-09 11:04:57

标签: android android-location

我希望在用户启用或禁用网络或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);
         } 
      }
    }
  }

这是我的Manifest的一小部分摘录

  <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>

如果广播中有额外的内容表明哪个提供商已更改以及是启用还是禁用,那么这将是完美的。不幸的是,这种情况并非如此。是否有人知道我可以通过哪种机制来确定哪些状态已经改变而不维护我自己的状态变量。

在一个理想的世界中,我会不断监视变化,但偶尔只会听取位置变化。我想避免不断监控位置变化。

4 个答案:

答案 0 :(得分:5)

这对我有用:

将接收器添加到清单文件:

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


    }

}

虽然这个接收器由于显而易见的原因被多次调用,但这会告诉你状态。

答案 1 :(得分: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也知道which provider is currently enabled

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

...这样您就可以将这些检查与BroadcastReceiver一起使用,以避免手动持有任何启用/禁用标志。 除此之外,还有一个名为android.location.GPS_ENABLED_CHANGE的意图,您可以尝试接收(和处理)。但由于此意图隐藏在官方文档中,因此使用它可能不安全,如this answer中所述。

甚至另一种方法:
Android的默认设置切换小部件(您知道我的意思)通过订阅android.location.PROVIDERS_CHANGED意图(与您一样)显示GPS启用/禁用状态,以通过用户设置触发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;
}

(来自official sources) 您也可以将此方法适用于其他位置提供商。

答案 2 :(得分:1)

感谢@usman的回答,我们可以通过以下方式在没有extends课程的情况下应用解决方案;

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

}

答案 3 :(得分:0)

在Receiver上,您只需检查哪些提供商已启用:

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

通过这种方式,您可以获得所有启用提供程序。