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

kle*_*gat 2 android location

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

我正在使用 android 开发人员文档附带的官方示例,但是我读过由于过度高效的实践,开发人员将 API 偏向于仅使用蜂窝数据和 Wi-Fi,除非 GPS_PROVIDER 被调用来轮询它的输出通过 locationManager 以便一旦应用程序请求,地理围栏实例可以主要从那里检索更精确的位置。但是我被困在代码的哪一部分添加此相关行,无论它是 java 文件夹中的单独类还是 Mainactivity 本身内部以及结构中的其他位置(除了权限形式的清单) ) 我是否必须参考它们的存在才能使其一致地工作。

欢迎任何帮助。

Kla*_*und 5

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

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

您的问题是:这样做的最佳方法是什么?


LocationManager 与 Google(Play 服务)位置 API

首先,重要的是要了解在过去几年中普遍推荐的获取位置更新的方式已经从通过 Android 的LocationManager(+ DIY 融合逻辑)手动但细粒度的位置更新设置转向更强大和方便的谷歌位置 API

我认为您知道这两者(以及作为位置 API 一部分的地理围栏 API),并且由于连接问题而排除了后者。那么让我们来看看如何使用LocationManager来做到这一点。


使用 LocationManager 获取更新

但是我被困在代码的哪一部分添加此相关行,无论它是 java 文件夹中的单独类还是 Mainactivity 本身内部以及结构中的其他位置(除了权限形式的清单) ) 我是否必须参考它们的存在才能使其一致地工作。

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

案例 1:仅在一个 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
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 创建一个自定义Application类,该类包含LocationManager实例并在应用程序生命周期中启动/停止它。我编写了一个简单的实用程序类,您可以使用它(您可以在此处阅读有关它的更多信息)。
  • 应用程序类也可以实现LocationListener接口,尽管将该逻辑打包到您自己的类(例如LocationHelper类)中并从您的应用程序中启动和停止该类可能更简洁。
  • 最后,通过事件总线(例如Green EventBusOtto)分发位置更新,以便任何 Activity、Fragment 或其他类都可以订阅这些更新,而无需知道这些位置来自何处。

检查地理围栏

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

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
        }
    }
Run Code Online (Sandbox Code Playgroud)

备注/提示

  • 您应该为 GPS 使用较高的更新间隔,以便当人们进入/离开您展览中的地理围栏时,您的应用程序可以快速做出反应。但是,这会消耗大量电池,因此请确保附近有备用电池/充电器。

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

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