【问题标题】:requestLocationUpdates with PendingIntent and Broadcast - what broadcasts do I getrequestLocationUpdates 与 PendingIntent 和广播 - 我得到什么广播
【发布时间】:2013-05-21 05:32:57
【问题描述】:

我设置了一个由 BroadcastReceiver 接收的警报,它启动了一个 WakefulIntentService(类LocationMonitor)。在LocationMonitor 我有:

private static final int MIN_TIME_BETWEEN_SCANS = 1 * 30 * 1000;
private static final int MIN_DISTANCE = 0;

@Override
protected void doWakefulWork(Intent intent) {
    final CharSequence action = intent.getAction();
    if (action == null) { // monitor command from the alarm manager
        // the call below enables the LocationReceiver
        BaseReceiver.enable(this, ENABLE, LocationReceiver.class);
        if (lm == null) lm = (LocationManager) this
                    .getSystemService(Context.LOCATION_SERVICE);
        Intent i = new Intent(this, LocationReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(this, NOT_USED, i,
            PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT);
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                MIN_TIME_BETWEEN_SCANS, MIN_DISTANCE, pi);
    } else if (ac_location_data.equals(action)) {
        final Bundle extras = intent.getExtras();
        if (extras != null) {
            final Location loc = (Location) extras
                    .get(LocationManager.KEY_LOCATION_CHANGED);
            if (loc == null) {
                w("NULL LOCATION  - EXTRAS : " + extras); //Log.w
                // while gps is disabled I keep getting this :
                // NULL LOCATION - EXTRAS : Bundle[{providerEnabled=false}]
            } else {
                final double lon = loc.getLongitude();
                final double lat = loc.getLatitude();
                w("latitude :" + lat + " -- longitude : " + lon);
            }
        }
    }
}

上面的代码有几个问题。

  1. 如果 GPS 最初禁用,然后我启用它,我会收到一堆 W/GpsLocationProvider(...): Unneeded remove listener for uid 1000。警告来自here。我在代码中找不到在哪里触发了侦听器的删除我也看不到它们在哪里被分配了 uid 1000apparently 系统服务器)。
  2. 当我启用 gps 时,我得到了预期的位置,然后是“RemoteException”

    LocationManagerService(...): RemoteException 在接收器上调用 onLocationChanged{4083ee68 Intent PendingIntent{4084e6b8: PendingIntentRecord{4083ef78 gr.uoa.di.monitoring.android broadcastIntent}}}mUpdateRecords: {gps=UpdateRecord{40838180 mProvider: gps mUid : 10064}}

    这不是一个真正的 RemoteException,只是一个 PendingIntent.CancelledException - 该消息非常具有误导性。或者我认为:它来自here,它调用this我的问题是:为什么要重用 Intent - FLAG_ONE_SHOT 不应该处理它吗?

但最重要的问题是:当我像这样注册 PendingIntent 时我希望收到什么意图我应该使用什么标志

请记住,我正在使用这种模式,因为我想让手机更新其位置即使在睡着时并且这实现了它(我确实得到了位置更新)。我尝试使用FLAG_ONE_SHOT 模拟requestSingleUpdate(2.3 中不可用)。

接收者:

public final class LocationReceiver extends BaseReceiver {

    private static final Class<? extends Monitor> MONITOR_CLASS =
        LocationMonitor.class;

    @Override
    public void onReceive(Context context, Intent intent) {
        d(intent.toString());
        final String action = intent.getAction();
        d(action + "");
        final Intent i = new Intent(context, MONITOR_CLASS);
        i.fillIn(intent, 0); // TODO do I need flags ?
        i.setAction(ac_location_data.toString());
        WakefulIntentService.sendWakefulWork(context, i);
    }
}

【问题讨论】:

    标签: android gps android-pendingintent location-provider


    【解决方案1】:

    对于这个问题:

    当我像这样注册 PendingIntent 时,我期望什么意图 收到 ?我应该使用什么标志?

    当您注册位置更新并传递PendingIntent 时,当LocationManager 决定通知您位置更新时,将触发此PendingIntent。你可以提供几乎任何你想要的东西,这取决于你想要在PendingIntent 被触发时发生什么。 LocationManager 将为发送的Intent 添加额外的内容。这个额外的有捆绑键LocationManager.KEY_LOCATION_CHANGED,与该键关联的对象是Location 对象。

    LocationManager 会一次又一次地使用这个PendingIntent 来通知你的应用程序位置更新,所以我认为使用PendingIntent.FLAG_ONE_SHOT 可能不是一个好主意。如果您只想要一次更新,为什么不在获得一次更新后取消注册?

    编辑:添加代码以在注册更新之前取消任何先前请求的更新

    在致电registerLocationUpdates() 之前,请执行以下操作以取消任何以前注册的更新:

        Intent i = new Intent(this, LocationReceiver.class);
        // Get any existing matching PendingIntent
        PendingIntent pi = PendingIntent.getBroadcast(this, NOT_USED, i,
            PendingIntent.FLAG_NO_CREATE);
        if (pi != null) {
            // Cancel any updates for this PendingIntent, because we are about to
            //  invalidate it
            lm.removeUpdates(pi);
        }
        // Create a new PendingIntent and cancel any previous one
        pi = PendingIntent.getBroadcast(this, NOT_USED, i,
                      PendingIntent.FLAG_CANCEL_CURRENT);
        // Now register for location updates...
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                MIN_TIME_BETWEEN_SCANS, MIN_DISTANCE, pi);
    

    注意:实际上,在这种情况下,我不知道您为什么需要取消任何以前的PendingIntent 并创建一个新的。你可以得到一个PendingIntent,如果你已经用那个PendingIntent注册了位置更新,我认为再次注册不会导致PendingIntent被多次使用。如果您想尝试这样做,您需要做的就是从现有代码中删除PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT。我认为这是一个更好/更清洁/更清晰的解决方案。

    【讨论】:

    • 谢谢!上面的代码由警报管理器定期触发,并且由于位置更新可能需要一些时间,如果取消注册会搞砸,我会徘徊(如何处理连续注册?)。确实搞砸了的是FLAG_CANCEL_CURRENT - 问题的其他部分是我试图准确理解为什么
    • FLAG_CANCEL_CURRENT 只是意味着任何匹配的PendingIntent 都应该失效(即:取消),并使用提供的参数、标志、附加信息等创建一个新的。
    • 啊...您正在重复注册位置更新并取消之前的PendingIntent。这意味着LocationManager 有回调请求,当它尝试发送回调时,PendingIntent 不再有效。
    • 您应该先用以前的PendingIntent 调用removeUpdates(),然后再用新的调用requestLocationUpdates()。我将在我的答案中添加一些示例代码。
    • 我在答案中添加了代码。这样做时,我意识到当您取消前一个并创建一个新的时,您实际上并没有以任何方式更改 PendingIntent,因此我在答案中添加了另一个(更简单)的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    相关资源
    最近更新 更多