在 Android Studio 上轮询 GPS 位置以增强 GeofencingApi 的正确程序

Proper procedure to poll GPS location for enhanced GeofencingApi on Android Studio

我不是程序员,但即便如此,我只是努力“混合”(从其他人的样本和说明)一个小型 android 艺术装置项目,该项目将在当地大学的户外展示校园。此应用程序将显示弹出窗口 windows,其中包含在穿过场地内相应的径向围栏时发生在该地点的事件的轶事叙述,需要不依赖数据载体或 Wi-Fi 提供商的位置获取因为该地区没有覆盖,而且即使在有网络和 wi-fi 信号可用的城市环境中进行测试,这些似乎也很不稳定。

我使用的是 android 开发人员文档附带的官方示例,但是我读到,由于实践效率过高,开发人员偏向 API 仅使用蜂窝网络数据和 wi-fi 除非 GPS_PROVIDER 被调用以通过 locationManager 轮询它的输出,这样一旦应用程序请求,geofence 实例就可以主要从那里检索更精确的位置。但是我不知道在代码的哪一部分添加这些相关行,无论它是 java 文件夹中的单独 class 还是在 Mainactivity 本身内部以及结构中的其他位置(除了权限形式的清单之外)我是否必须参考它们的存在才能连贯地工作。

欢迎任何帮助。

根据您的描述,我了解到您有几个限制条件。让我解释一下我的理解:

  • 您想在多个设备上为展览/艺术装置部署位置感知应用程序。
  • 设备将没有连接(没有 WiFi,没有蜂窝网络),因此只需要使用 GPS。
  • 您想检测每个设备何时进入预定义区域,即兴趣点周围的固定半径。

您的问题是:最好的方法是什么?


LocationManager 与 Google(播放服务)位置 API

首先,重要的是要了解获取位置更新的普遍推荐方式在过去几年发生了变化,不再是通过 Android 的 LocationManager (+ DIY fusion logic) towards the more powerful and convenient Google Location APIs.

我认为你知道两者(以及 Geofencing API 是位置 APIs 的一部分)并且由于连接问题已经排除了后者。那么让我们来看看如何使用 LocationManager.


使用 LocationManager 获取更新

But I am stuck as to in which portion of the code to add this pertaining lines whether it be a separate class within the java folder or inside the Mainactivity itself as well as to where else in the structure (aside the manifest in the form of permissions) do i have to reference their existence for it to work coherently.

您是从 Activity 还是其他地方使用 LocationManager 主要取决于您是只需要一个 Activity 还是多个 Activity 位置更新。

情况一:位置只有一个Activity

您可以在 Activity 的生命周期内安全地实例化、启动和停止管理器。

public MyActivity extends Activity implements LocationListener {

    private LocationManager locationManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    }

    @Override
    protected void onResume() {
        super.onResume();
        ...
        // Request GPS updates every second (careful: high battery drain)
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5, this);
    }

    @Override
    protected void onPause() {
        locationManager.removeUpdates(this);
        super.onPause();
    }

    @Override
    public void onLocationChanged(Location location) {
        // Do something with the location
    }

    // Implement other LocationListener interface methods here, handle provider status changes
}

案例 2:多个活动中的位置

详细的代码示例超出了这个答案的范围,但让我提供一个草图:

  • 创建自定义 Application class that holds the LocationManager instance and start/stops it with the application lifecycle. I have written a simple utility class that you can use for this (you can read more about it here).
  • 应用程序 class 也可以实现 LocationListener 接口,尽管将该逻辑打包到您自己的 class 中可能更清晰(例如,一个 LocationHelper class) 并从您的应用程序启动和停止 class。
  • 最后,通过事件总线分发位置更新(例如 Green EventBus or Otto),这样任何 Activity、片段或其他 class 都可以订阅这些更新而无需知道在哪里这些位置来自。

检查地理围栏

为了简单起见,我们假设您只使用一个 Activity 和一个地理围栏。然后您可以检查该地理围栏中当前位置的 inclusion/exclusion,如下所示:

public MyActivity extends Activity implements LocationListener {

    // Define a hard-coded POI and geofence radius
    private static final Location POI_A = new Location("dummy");
    static {
        POI_A.setLongitude(/* POI longitude */);
        POI_A.setLatitude(/* POI latitude */);
    }
    private static final int GEOFENCE_RADIUS = 50; // meters

    ...

    @Override
    public void onLocationChanged(Location location) {
        if (location.distanceTo(POI_A) <= GEOFENCE_RADIUS) {
            // Location is within geofence of point of interest A
        } else {
            // Location is outside the geofence of point of interest A
        }
    }

备注/提示

  • 您应该为 GPS 使用较高的更新间隔,以便您的应用程序可以在人们 enter/leave 展览中的地理围栏时快速做出反应。但是,这会消耗大量电池,因此请务必在附近准备好备用电池/充电器。

  • 如果没有任何连接,设备可能需要很长时间才能找到 GPS 定位(因为没有机会使用 Assisted GPS)。 如果您可以在展览区提供任何类型的连接(例如,单个 WiFi 热点),这可以大大加快您的应用程序启动和获取位置所需的时间,即使您仅使用 GPS.

  • 由于位置读数可能会跳跃几米,您可能应该使用滞后来构建地理围栏(例如,当用户距离小于 40 米时触发 enter 事件,并且 leave 超过60m时的事件)避免在POI圈边缘重复转换。