如何提高Android地理围栏进入/退出通知的一致性?

25

我正在使用内置的地理围栏API(Play服务)并且结果不尽如人意。即使开启了GPS,且已经连接了位置客户端(LocationClient)在后台运行,设置地理围栏后,进入/离开通知的触发非常不确定。我开始监控(轮询)位置变化和距离,并在调试文本字段中看到,即使基于设备注册的位置和地理围栏位置,我在技术上仍然在/在外面地理围栏之内,有时会触发通知,有时却不会。有没有办法让这更加可预测?我几乎想放弃这个API,实现自己的(耗电)地理围栏,基于对设备位置的轮询。

2个回答

45
一些建议:
  1. 确保使用BroadcastReceiver而不是Service接收转换,否则如果您的应用程序被杀死/关闭,则可能无法获取它。如此处所述: Android地理围栏最终无法获取转换意图

  2. 在设备重新启动后,请确保重新创建您的地理围栏,最好使用一个boot-broadcast receiver。 如此处所述:设备重新启动后,Android的地理围栏是否仍然处于活动状态

  3. 另一个常见误解,这使我感到困惑,因为它与IOS不同,即如果设备在创建时发现您在地理围栏内部,您将立即获得触发器。我自己使用“优雅期”解决了这个问题,在此主题中解释了这一点

最后一个重要的事情:如果您遵循以上几点,则您的应用程序连接或未连接LocationClient都不应该有任何影响。我在代码中添加或删除Geofences的过程基本上是:

  1. 创建并连接locationclient。

  2. 在连接回调中,进行geofence(s)的添加/删除

  3. 在geofence-result回调中,断开locationclient。

每次发生这种情况时,我的位置客户端总共只连接了几秒钟。操作系统仍将产生地理围栏警报,并在发生时调用我的BroadcastReceiver。

如果您做到这些,我敢打赌您的体验会得到改善。

希望能对你有所帮助!


我会尝试第一步。虽然这些信息总体上很有用,但在我的项目中不适用于第二步和第三步。另外,知道LocationClient在这方面并不是一个相关的部分,因为我花了一些精力来保持它的热度,并且定期更新位置。消除这些将使应用程序更轻便、更省电/资源。 - oviroa
太棒了,很高兴我能帮上忙! - Mathias
1
不幸的是,在进行建议的更新后,没有任何改进。此外,这个语句“如果你遵循上述要点,在你的应用程序中连接LocationClient或不连接都不应该有影响。”似乎并不准确,因为在某些情况下,当客户端断开连接时,我没有收到任何通知,但是一旦我连接,它们就开始出现了。所有这一切都非常令人沮丧,因为我的项目的重要功能取决于一些理论上应该正常工作的东西,但实际上却失败了。 - oviroa
2
抱歉,你仍然遇到问题。但我相信,你不需要连接LocationClient来获取回调。LocationClient是执行位置相关操作的“通道”。我认为它就像打电话一样。我的广播意图在我们的应用程序被销毁后,甚至在手机重启后也能得到回调,而无需实际启动我们的应用程序,所以我非常确定它可以工作。如果你查看LocationClient的APIDocs,基本上也是这么说的。希望你能解决问题,伙计! - Mathias
1
Leon,是的,我已经在答案中写了。"如果设备在创建地理围栏时发现您在其内部"。 - Mathias
显示剩余7条评论

0

我尝试了所有被接受的回答中的建议,但对我来说准确度并没有提高。如果您在这里寻找更多想法,您应该阅读以下内容。

我能够通过基于安卓位置APIJTS位置套件的自己的地理围栏算法来解决问题。

为了更精确,您所需做的就是创建一个代表您的围栏的jts多边形。

static GeometryFactory GF = new GeometryFactory();

public Polygon getPolygon() {
    ArrayList<Coordinate> coors = new ArrayList<>();
    
    for (Point p : getPolygonPoints()) {
        coors.add(new Coordinate(p.lat, p.lon));
    }

    // close the polygon is needs
    final Coordinate first = coors.get(0);
    final Coordinate last = coors.get(coors.size()-1);
    if (!first.equals2D(last)) {
        coors.add(coors.get(0));
    }

    // create polygon
    return GF.createPolygon(coors.toArray(new Coordinate[] {}));
}

然后您可以检查当前GPS点是否在给定的多边形内部。

final Point point = GF.createPoint(new Coordinate(lat, lon));
if (point.within(getPolygon())) {
   // hit
} else {
   // miss
}

就是这样了。然后,您可以创建一个java.util.Timer来定期迭代多边形(地理围栏)列表,以知道哪个被击中或在后面。

注意:将以下内容添加到您的模块build.gradle中,以在项目中添加JTS库:

implementation(group: 'org.locationtech.jts.io', name: 'jts-io-common', version: '1.18.1') {
   exclude(group: 'org.hamcrest')
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接